This reverts commit6681113633which is commitbcc80dec91upstream. The dependant patch before this one caused build errors in the 6.6.y tree, so revert this for now so that we can fix them up properly. Reported-by: Ignat Korchagin <ignat@cloudflare.com> Link: https://lore.kernel.org/r/3DB3A6D3-0D3A-4682-B4FA-407B2D3263B2@cloudflare.com Reported-by: Lars Wendler <wendler.lars@web.de> Link: https://lore.kernel.org/r/20250110103328.0e3906a8@chagall.paradoxon.rec Reported-by: Chris Clayton <chris2553@googlemail.com> Link: https://lore.kernel.org/r/10c7be00-b1f8-4389-801b-fb2d0b22468d@googlemail.com Cc: Dexuan Cui <decui@microsoft.com> Cc: Naman Jain <namjain@linux.microsoft.com> Cc: Michael Kelley <mhklinux@outlook.com> Cc: Wei Liu <wei.liu@kernel.org> Cc: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
116 lines
3.2 KiB
C
116 lines
3.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
* Definitions for the clocksource provided by the Hyper-V
|
|
* hypervisor to guest VMs, as described in the Hyper-V Top
|
|
* Level Functional Spec (TLFS).
|
|
*
|
|
* Copyright (C) 2019, Microsoft, Inc.
|
|
*
|
|
* Author: Michael Kelley <mikelley@microsoft.com>
|
|
*/
|
|
|
|
#ifndef __CLKSOURCE_HYPERV_TIMER_H
|
|
#define __CLKSOURCE_HYPERV_TIMER_H
|
|
|
|
#include <linux/clocksource.h>
|
|
#include <linux/math64.h>
|
|
#include <asm/hyperv-tlfs.h>
|
|
|
|
#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
|
|
#define HV_MIN_DELTA_TICKS 1
|
|
|
|
#ifdef CONFIG_HYPERV_TIMER
|
|
|
|
#include <asm/hyperv_timer.h>
|
|
|
|
/* Routines called by the VMbus driver */
|
|
extern int hv_stimer_alloc(bool have_percpu_irqs);
|
|
extern int hv_stimer_cleanup(unsigned int cpu);
|
|
extern void hv_stimer_legacy_init(unsigned int cpu, int sint);
|
|
extern void hv_stimer_legacy_cleanup(unsigned int cpu);
|
|
extern void hv_stimer_global_cleanup(void);
|
|
extern void hv_stimer0_isr(void);
|
|
|
|
extern void hv_init_clocksource(void);
|
|
extern void hv_remap_tsc_clocksource(void);
|
|
|
|
extern unsigned long hv_get_tsc_pfn(void);
|
|
extern struct ms_hyperv_tsc_page *hv_get_tsc_page(void);
|
|
|
|
static __always_inline bool
|
|
hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg,
|
|
u64 *cur_tsc, u64 *time)
|
|
{
|
|
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 false;
|
|
/*
|
|
* 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 = hv_get_raw_timer();
|
|
|
|
/*
|
|
* Make sure we read sequence after we read all other values
|
|
* from TSC page.
|
|
*/
|
|
smp_rmb();
|
|
|
|
} while (READ_ONCE(tsc_pg->tsc_sequence) != sequence);
|
|
|
|
*time = mul_u64_u64_shr(*cur_tsc, scale, 64) + offset;
|
|
return true;
|
|
}
|
|
|
|
#else /* CONFIG_HYPERV_TIMER */
|
|
static inline unsigned long hv_get_tsc_pfn(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline struct ms_hyperv_tsc_page *hv_get_tsc_page(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static __always_inline bool
|
|
hv_read_tsc_page_tsc(const struct ms_hyperv_tsc_page *tsc_pg, u64 *cur_tsc, u64 *time)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static inline int hv_stimer_cleanup(unsigned int cpu) { return 0; }
|
|
static inline void hv_stimer_legacy_init(unsigned int cpu, int sint) {}
|
|
static inline void hv_stimer_legacy_cleanup(unsigned int cpu) {}
|
|
static inline void hv_stimer_global_cleanup(void) {}
|
|
static inline void hv_stimer0_isr(void) {}
|
|
|
|
#endif /* CONFIG_HYPERV_TIMER */
|
|
|
|
#endif
|