From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Michael Kelley <mikelley@microsoft.com>
Date: Mon, 28 Feb 2022 08:41:24 -0800
Subject: arm64: hyperv: Enable Hyper-V synthetic clocks/timers

This patch adds support for Hyper-V synthetic clocks and timers on
ARM64. Upstream code assumes changes to Hyper-V that were made
in Fall 2021 that fully virtualize the ARM64 architectural counter
and timer so that the driver in drivers/clocksource/arm_arch_timer.c
can be used.  But older versions of Hyper-V don't have this
support and must use the Hyper-V synthetic clocks and timers.
As such, this patch is out-of-tree code.

This patch does two related things. First it splits the general
Hyper-V initialization code to create hyperv_early_init() that runs
much earlier during kernel boot. This early init function is needed
so that core Hyper-V functionality is ready before the synthetic clocks
and timers are initialized. Second, it adds Hyper-V clock and timer
initialization via TIMER_ACPI_DECLARE() and hyperv_timer_init()
in the Hyper-V clocksource driver in drivers/clocksource/hyperv_timer.c.

Signed-off-by: Michael Kelley <mikelley@microsoft.com>
[tyhicks: Forward port around a minor text conflict caused by commit
 245b993d8f6c ("clocksource: hyper-v: unexport __init-annotated
 hv_init_clocksource()")
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
[kms: Forward port to 6.1]
Signed-off-by: Kelsey Steele <kelseysteele@microsoft.com>
---
 arch/arm64/hyperv/mshyperv.c       | 15 +++++---
 arch/arm64/include/asm/mshyperv.h  | 18 ++++++++++
 arch/arm64/kernel/setup.c          |  4 +++
 drivers/clocksource/hyperv_timer.c | 14 ++++++++
 drivers/hv/Kconfig                 |  2 +-
 5 files changed, 47 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index a406454578f0..0a868d490ef5 100644
--- a/arch/arm64/hyperv/mshyperv.c
+++ b/arch/arm64/hyperv/mshyperv.c
@@ -19,12 +19,11 @@
 
 static bool hyperv_initialized;
 
-static int __init hyperv_init(void)
+void __init hyperv_early_init(void)
 {
 	struct hv_get_vp_registers_output	result;
 	u32	a, b, c, d;
 	u64	guest_id;
-	int	ret;
 
 	/*
 	 * Allow for a kernel built with CONFIG_HYPERV to be running in
@@ -32,10 +31,10 @@ static int __init hyperv_init(void)
 	 * In such cases, do nothing and return success.
 	 */
 	if (acpi_disabled)
-		return 0;
+		return;
 
 	if (strncmp((char *)&acpi_gbl_FADT.hypervisor_id, "MsHyperV", 8))
-		return 0;
+		return;
 
 	/* Setup the guest ID */
 	guest_id = hv_generate_guest_id(LINUX_VERSION_CODE);
@@ -63,6 +62,13 @@ static int __init hyperv_init(void)
 	pr_info("Hyper-V: Host Build %d.%d.%d.%d-%d-%d\n",
 		b >> 16, b & 0xFFFF, a,	d & 0xFFFFFF, c, d >> 24);
 
+	hyperv_initialized = true;
+}
+
+static int __init hyperv_init(void)
+{
+	int ret;
+
 	ret = hv_common_init();
 	if (ret)
 		return ret;
@@ -74,7 +80,6 @@ static int __init hyperv_init(void)
 		return ret;
 	}
 
-	hyperv_initialized = true;
 	return 0;
 }
 
diff --git a/arch/arm64/include/asm/mshyperv.h b/arch/arm64/include/asm/mshyperv.h
index f87a450e5b6b..713bebd87d6c 100644
--- a/arch/arm64/include/asm/mshyperv.h
+++ b/arch/arm64/include/asm/mshyperv.h
@@ -21,6 +21,13 @@
 #include <linux/types.h>
 #include <linux/arm-smccc.h>
 #include <asm/hyperv-tlfs.h>
+#include <clocksource/arm_arch_timer.h>
+
+#if IS_ENABLED(CONFIG_HYPERV)
+void __init hyperv_early_init(void);
+#else
+static inline void hyperv_early_init(void) {};
+#endif
 
 extern u64 hv_do_hvc(u64 control, ...);
 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)
 	return hv_get_vpreg(reg);
 }
 
+/* Define the interrupt ID used by STIMER0 Direct Mode interrupts. This
+ * value can't come from ACPI tables because it is needed before the
+ * Linux ACPI subsystem is initialized.
+ */
+#define HYPERV_STIMER0_VECTOR	31
+
+static inline u64 hv_get_raw_timer(void)
+{
+	return arch_timer_read_counter();
+}
+
 /* SMCCC hypercall parameters */
 #define HV_SMCCC_FUNC_NUMBER	1
 #define HV_FUNC_ID	ARM_SMCCC_CALL_VAL(			\
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index fea3223704b6..b4e4f3e6ea20 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -50,6 +50,7 @@
 #include <asm/traps.h>
 #include <asm/efi.h>
 #include <asm/xen/hypervisor.h>
+#include <asm/mshyperv.h>
 #include <asm/mmu_context.h>
 
 static int num_standard_resources;
@@ -343,6 +344,9 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
 	if (acpi_disabled)
 		unflatten_device_tree();
 
+	/* Do after acpi_boot_table_init() so local FADT is available */
+	hyperv_early_init();
+
 	bootmem_init();
 
 	kasan_init();
diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
index 18de1f439ffd..bccbeab3fa46 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -566,3 +566,17 @@ void __init hv_init_clocksource(void)
 	hv_sched_clock_offset = hv_read_reference_counter();
 	hv_setup_sched_clock(read_hv_sched_clock_msr);
 }
+
+/* Initialize everything on ARM64 */
+static int __init hyperv_timer_init(struct acpi_table_header *table)
+{
+	if (!hv_is_hyperv_initialized())
+		return -EINVAL;
+
+	hv_init_clocksource();
+	if (hv_stimer_alloc(true))
+		return -EINVAL;
+
+	return 0;
+}
+TIMER_ACPI_DECLARE(hyperv, ACPI_SIG_GTDT, hyperv_timer_init);
diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
index 0747a8f1fcee..6802f981ba8c 100644
--- a/drivers/hv/Kconfig
+++ b/drivers/hv/Kconfig
@@ -14,7 +14,7 @@ config HYPERV
 	  system.
 
 config HYPERV_TIMER
-	def_bool HYPERV && X86
+	def_bool HYPERV
 
 config HYPERV_UTILS
 	tristate "Microsoft Hyper-V Utilities driver"
-- 
Armbian

