Skip to content

Commit 63d444e

Browse files
committed
Merge feature/arm64-hyperv-synthetic-clocks-timers/6.6 into v6.6.75
* commit '27ff58a87b8e8f33461b2443efe4dfa6487ad352': x86/hyperv: Don’t enable TSCInvariant on some older Hyper-V hosts mshyperv: Introduce hv_get_hypervisor_version function arm64: hyperv: Fix build breakage for non-ARM64 architectures arm64: hyperv: Enable Hyper-V synthetic clocks/timers
2 parents 568566c + 27ff58a commit 63d444e

File tree

10 files changed

+132
-35
lines changed

10 files changed

+132
-35
lines changed

arch/arm64/hyperv/mshyperv.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,29 @@
1919

2020
static bool hyperv_initialized;
2121

22-
static int __init hyperv_init(void)
22+
int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
23+
{
24+
hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION,
25+
(struct hv_get_vp_registers_output *)info);
26+
27+
return 0;
28+
}
29+
30+
void __init hyperv_early_init(void)
2331
{
2432
struct hv_get_vp_registers_output result;
25-
u32 a, b, c, d;
2633
u64 guest_id;
27-
int ret;
2834

2935
/*
3036
* Allow for a kernel built with CONFIG_HYPERV to be running in
3137
* a non-Hyper-V environment, including on DT instead of ACPI.
3238
* In such cases, do nothing and return success.
3339
*/
3440
if (acpi_disabled)
35-
return 0;
41+
return;
3642

3743
if (strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8))
38-
return 0;
44+
return;
3945

4046
/* Setup the guest ID */
4147
guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
@@ -54,14 +60,12 @@ static int __init hyperv_init(void)
5460
ms_hyperv.features, ms_hyperv.priv_high, ms_hyperv.hints,
5561
ms_hyperv.misc_features);
5662

57-
/* Get information about the Hyper-V host version */
58-
hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION, &result);
59-
a = result.as32.a;
60-
b = result.as32.b;
61-
c = result.as32.c;
62-
d = result.as32.d;
63-
pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
64-
b >> 16, b & 0xFFFF, a, d & 0xFFFFFF, c, d >> 24);
63+
hyperv_initialized = true;
64+
}
65+
66+
static int __init hyperv_init(void)
67+
{
68+
int ret;
6569

6670
ret = hv_common_init();
6771
if (ret)
@@ -74,7 +78,6 @@ static int __init hyperv_init(void)
7478
return ret;
7579
}
7680

77-
hyperv_initialized = true;
7881
return 0;
7982
}
8083

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_ARM64_HYPERV_TIMER_H
3+
#define _ASM_ARM64_HYPERV_TIMER_H
4+
5+
#include <asm/mshyperv.h>
6+
7+
#endif

arch/arm64/include/asm/mshyperv.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@
2121
#include <linux/types.h>
2222
#include <linux/arm-smccc.h>
2323
#include <asm/hyperv-tlfs.h>
24+
#include <clocksource/arm_arch_timer.h>
25+
26+
#if IS_ENABLED(CONFIG_HYPERV)
27+
void __init hyperv_early_init(void);
28+
#else
29+
static inline void hyperv_early_init(void) {};
30+
#endif
2431

2532
extern u64 hv_do_hvc(u64 control, ...);
2633
extern u64 hv_do_hvc_fast_get(u64 control, u64 input1, u64 input2, u64 input3,
@@ -45,6 +52,17 @@ static inline u64 hv_get_register(unsigned int reg)
4552
return hv_get_vpreg(reg);
4653
}
4754

55+
/* Define the interrupt ID used by STIMER0 Direct Mode interrupts. This
56+
* value can't come from ACPI tables because it is needed before the
57+
* Linux ACPI subsystem is initialized.
58+
*/
59+
#define HYPERV_STIMER0_VECTOR 31
60+
61+
static inline u64 hv_get_raw_timer(void)
62+
{
63+
return arch_timer_read_counter();
64+
}
65+
4866
/* SMCCC hypercall parameters */
4967
#define HV_SMCCC_FUNC_NUMBER 1
5068
#define HV_FUNC_ID ARM_SMCCC_CALL_VAL( \

arch/arm64/kernel/setup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <asm/traps.h>
5353
#include <asm/efi.h>
5454
#include <asm/xen/hypervisor.h>
55+
#include <asm/mshyperv.h>
5556
#include <asm/mmu_context.h>
5657

5758
static int num_standard_resources;
@@ -358,6 +359,9 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
358359
if (acpi_disabled)
359360
unflatten_device_tree();
360361

362+
/* Do after acpi_boot_table_init() so local FADT is available */
363+
hyperv_early_init();
364+
361365
bootmem_init();
362366

363367
kasan_init();

arch/x86/kernel/cpu/mshyperv.c

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -404,13 +404,26 @@ static void __init reduced_hw_init(void)
404404
x86_init.irqs.pre_vector_init = x86_init_noop;
405405
}
406406

407+
int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
408+
{
409+
unsigned int hv_max_functions;
410+
411+
hv_max_functions = cpuid_eax(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS);
412+
if (hv_max_functions < HYPERV_CPUID_VERSION) {
413+
pr_err("%s: Could not detect Hyper-V version\n", __func__);
414+
return -ENODEV;
415+
}
416+
417+
cpuid(HYPERV_CPUID_VERSION, &info->eax, &info->ebx, &info->ecx, &info->edx);
418+
419+
return 0;
420+
}
421+
407422
static void __init ms_hyperv_init_platform(void)
408423
{
424+
union hv_hypervisor_version_info version;
425+
unsigned int build = 0;
409426
int hv_max_functions_eax;
410-
int hv_host_info_eax;
411-
int hv_host_info_ebx;
412-
int hv_host_info_ecx;
413-
int hv_host_info_edx;
414427

415428
#ifdef CONFIG_PARAVIRT
416429
pv_info.name = "Hyper-V";
@@ -436,6 +449,18 @@ static void __init ms_hyperv_init_platform(void)
436449
pr_debug("Hyper-V: max %u virtual processors, %u logical processors\n",
437450
ms_hyperv.max_vp_index, ms_hyperv.max_lp_index);
438451

452+
/*
453+
* Host builds earlier than 22621 (Win 11 22H2) have a bug in the
454+
* invariant TSC feature that may result in the guest seeing a "slow"
455+
* TSC after host hibernation. This causes problems with synthetic
456+
* timer interrupts. In such a case, avoid the bug by assuming the
457+
* feature is not present.
458+
*/
459+
if (!hv_get_hypervisor_version(&version))
460+
build = version.build_number;
461+
if (build < 22621)
462+
ms_hyperv.features &= ~HV_ACCESS_TSC_INVARIANT;
463+
439464
/*
440465
* Check CPU management privilege.
441466
*
@@ -461,21 +486,6 @@ static void __init ms_hyperv_init_platform(void)
461486
pr_info("Hyper-V: running on a nested hypervisor\n");
462487
}
463488

464-
/*
465-
* Extract host information.
466-
*/
467-
if (hv_max_functions_eax >= HYPERV_CPUID_VERSION) {
468-
hv_host_info_eax = cpuid_eax(HYPERV_CPUID_VERSION);
469-
hv_host_info_ebx = cpuid_ebx(HYPERV_CPUID_VERSION);
470-
hv_host_info_ecx = cpuid_ecx(HYPERV_CPUID_VERSION);
471-
hv_host_info_edx = cpuid_edx(HYPERV_CPUID_VERSION);
472-
473-
pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
474-
hv_host_info_ebx >> 16, hv_host_info_ebx & 0xFFFF,
475-
hv_host_info_eax, hv_host_info_edx & 0xFFFFFF,
476-
hv_host_info_ecx, hv_host_info_edx >> 24);
477-
}
478-
479489
if (ms_hyperv.features & HV_ACCESS_FREQUENCY_MSRS &&
480490
ms_hyperv.misc_features & HV_FEATURE_FREQUENCY_MSRS_AVAILABLE) {
481491
x86_platform.calibrate_tsc = hv_get_tsc_khz;

drivers/clocksource/hyperv_timer.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,11 @@ static __always_inline u64 read_hv_clock_msr(void)
377377
* noinstr. Notable; while HV_REGISTER_TIME_REF_COUNT is a synthetic
378378
* register it doesn't need the GHCB path.
379379
*/
380+
#ifdef CONFIG_ARM64
381+
return hv_get_register(HV_REGISTER_TIME_REF_COUNT);
382+
#else
380383
return hv_raw_get_register(HV_REGISTER_TIME_REF_COUNT);
384+
#endif
381385
}
382386

383387
/*
@@ -391,7 +395,12 @@ static __always_inline u64 read_hv_clock_msr(void)
391395
static union {
392396
struct ms_hyperv_tsc_page page;
393397
u8 reserved[PAGE_SIZE];
394-
} tsc_pg __bss_decrypted __aligned(PAGE_SIZE);
398+
} tsc_pg
399+
#ifdef CONFIG_ARM64
400+
__aligned(PAGE_SIZE);
401+
#else
402+
__bss_decrypted __aligned(PAGE_SIZE);
403+
#endif
395404

396405
static struct ms_hyperv_tsc_page *tsc_page = &tsc_pg.page;
397406
static unsigned long tsc_pfn;
@@ -624,3 +633,17 @@ void __init hv_remap_tsc_clocksource(void)
624633
if (!tsc_page)
625634
pr_err("Failed to remap Hyper-V TSC page.\n");
626635
}
636+
637+
/* Initialize everything on ARM64 */
638+
static int __init hyperv_timer_init(struct acpi_table_header *table)
639+
{
640+
if (!hv_is_hyperv_initialized())
641+
return -EINVAL;
642+
643+
hv_init_clocksource();
644+
if (hv_stimer_alloc(true))
645+
return -EINVAL;
646+
647+
return 0;
648+
}
649+
TIMER_ACPI_DECLARE(hyperv, ACPI_SIG_GTDT, hyperv_timer_init);

drivers/hv/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ config HYPERV_VTL_MODE
3939
If unsure, say N
4040

4141
config HYPERV_TIMER
42-
def_bool HYPERV && X86
42+
def_bool HYPERV
4343

4444
config HYPERV_UTILS
4545
tristate "Microsoft Hyper-V Utilities driver"

drivers/hv/hv_common.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ static void hv_kmsg_dump_register(void)
279279
int __init hv_common_init(void)
280280
{
281281
int i;
282+
union hv_hypervisor_version_info version;
283+
284+
/* Get information about the Hyper-V host version */
285+
if (!hv_get_hypervisor_version(&version))
286+
pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
287+
version.major_version, version.minor_version,
288+
version.build_number, version.service_number,
289+
version.service_pack, version.service_branch);
282290

283291
if (hv_is_isolation_supported())
284292
sysctl_record_panic_msg = 0;

include/asm-generic/hyperv-tlfs.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,29 @@ struct hv_input_unmap_device_interrupt {
787787
#define HV_SOURCE_SHADOW_NONE 0x0
788788
#define HV_SOURCE_SHADOW_BRIDGE_BUS_RANGE 0x1
789789

790+
/*
791+
* Version info reported by hypervisor
792+
*/
793+
union hv_hypervisor_version_info {
794+
struct {
795+
u32 build_number;
796+
797+
u32 minor_version : 16;
798+
u32 major_version : 16;
799+
800+
u32 service_pack;
801+
802+
u32 service_number : 24;
803+
u32 service_branch : 8;
804+
};
805+
struct {
806+
u32 eax;
807+
u32 ebx;
808+
u32 ecx;
809+
u32 edx;
810+
};
811+
};
812+
790813
/*
791814
* The whole argument should fit in a page to be able to pass to the hypervisor
792815
* in one hypercall.

include/asm-generic/mshyperv.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ static inline int cpumask_to_vpset_skip(struct hv_vpset *vpset,
275275
return __cpumask_to_vpset(vpset, cpus, func);
276276
}
277277

278+
int hv_get_hypervisor_version(union hv_hypervisor_version_info *info);
278279
void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die);
279280
bool hv_is_hyperv_initialized(void);
280281
bool hv_is_hibernation_supported(void);

0 commit comments

Comments
 (0)