fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 1) /* SPDX-License-Identifier: GPL-2.0 */
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 2)
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 3) /*
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 4) * Definitions for the clocksource provided by the Hyper-V
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 5) * hypervisor to guest VMs, as described in the Hyper-V Top
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 6) * Level Functional Spec (TLFS).
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 7) *
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 8) * Copyright (C) 2019, Microsoft, Inc.
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 9) *
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 10) * Author: Michael Kelley <mikelley@microsoft.com>
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 11) */
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 12)
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 13) #ifndef __CLKSOURCE_HYPERV_TIMER_H
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 14) #define __CLKSOURCE_HYPERV_TIMER_H
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 15)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 16) #include <linux/clocksource.h>
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 17) #include <linux/math64.h>
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 18) #include <asm/mshyperv.h>
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 19)
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 20) #define HV_MAX_MAX_DELTA_TICKS 0xffffffff
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 21) #define HV_MIN_DELTA_TICKS 1
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 22)
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 23) /* Routines called by the VMbus driver */
ec866be6ec547 (Michael Kelley 2021-03-02 13:38:22 -0800 24) extern int hv_stimer_alloc(bool have_percpu_irqs);
4df4cb9e99f83 (Michael Kelley 2019-11-13 01:11:49 +0000 25) extern int hv_stimer_cleanup(unsigned int cpu);
4df4cb9e99f83 (Michael Kelley 2019-11-13 01:11:49 +0000 26) extern void hv_stimer_legacy_init(unsigned int cpu, int sint);
4df4cb9e99f83 (Michael Kelley 2019-11-13 01:11:49 +0000 27) extern void hv_stimer_legacy_cleanup(unsigned int cpu);
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 28) extern void hv_stimer_global_cleanup(void);
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 29) extern void hv_stimer0_isr(void);
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 30)
3e2d94535adb2 (Vitaly Kuznetsov 2019-08-22 10:36:30 +0200 31) #ifdef CONFIG_HYPERV_TIMER
0af3e137c1443 (Andrea Parri 2020-01-09 17:06:49 +0100 32) extern u64 (*hv_read_reference_counter)(void);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 33) extern void hv_init_clocksource(void);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 34)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 35) extern struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 36)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 37) static inline notrace u64
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 38) hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg, u64 *cur_tsc)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 39) {
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 40) u64 scale, offset;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 41) u32 sequence;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 42)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 43) /*
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 44) * The protocol for reading Hyper-V TSC page is specified in Hypervisor
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 45) * Top-Level Functional Specification ver. 3.0 and above. To get the
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 46) * reference time we must do the following:
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 47) * - READ ReferenceTscSequence
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 48) * A special '0' value indicates the time source is unreliable and we
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 49) * need to use something else. The currently published specification
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 50) * versions (up to 4.0b) contain a mistake and wrongly claim '-1'
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 51) * instead of '0' as the special value, see commit c35b82ef0294.
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 52) * - ReferenceTime =
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 53) * ((RDTSC() * ReferenceTscScale) >> 64) + ReferenceTscOffset
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 54) * - READ ReferenceTscSequence again. In case its value has changed
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 55) * since our first reading we need to discard ReferenceTime and repeat
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 56) * the whole sequence as the hypervisor was updating the page in
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 57) * between.
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 58) */
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 59) do {
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 60) sequence = READ_ONCE(tsc_pg->tsc_sequence);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 61) if (!sequence)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 62) return U64_MAX;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 63) /*
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 64) * Make sure we read sequence before we read other values from
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 65) * TSC page.
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 66) */
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 67) smp_rmb();
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 68)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 69) scale = READ_ONCE(tsc_pg->tsc_scale);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 70) offset = READ_ONCE(tsc_pg->tsc_offset);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 71) *cur_tsc = hv_get_raw_timer();
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 72)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 73) /*
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 74) * Make sure we read sequence after we read all other values
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 75) * from TSC page.
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 76) */
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 77) smp_rmb();
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 78)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 79) } while (READ_ONCE(tsc_pg->tsc_sequence) != sequence);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 80)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 81) return mul_u64_u64_shr(*cur_tsc, scale, 64) + offset;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 82) }
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 83)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 84) static inline notrace u64
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 85) hv_read_tsc_page(const struct ms_hyperv_tsc_page *tsc_pg)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 86) {
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 87) u64 cur_tsc;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 88)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 89) return hv_read_tsc_page_tsc(tsc_pg, &cur_tsc);
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 90) }
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 91)
3e2d94535adb2 (Vitaly Kuznetsov 2019-08-22 10:36:30 +0200 92) #else /* CONFIG_HYPERV_TIMER */
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 93) static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 94) {
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 95) return NULL;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 96) }
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 97)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 98) static inline u64 hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 99) u64 *cur_tsc)
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 100) {
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 101) return U64_MAX;
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 102) }
3e2d94535adb2 (Vitaly Kuznetsov 2019-08-22 10:36:30 +0200 103) #endif /* CONFIG_HYPERV_TIMER */
dd2cb348613b4 (Michael Kelley 2019-07-01 04:26:06 +0000 104)
fd1fea6834d0f (Michael Kelley 2019-07-01 04:25:56 +0000 105) #endif