From: Jeremy Linton <jeremy.linton(a)arm.com>
NOT_UPSTREAM/HYPERV: Enable HYPERV_TIMER on ARM64
Bugzilla:
https://bugzilla.redhat.com/show_bug.cgi?id=2007430
Upstream Status: RHEL-only
The existing windows/arm64 hyperv host expects that HYPERV_TIMER
is enabled by the linux guests (as x86), and so guests that
aren't utilizing this will fail to boot fairly early in the
boot cycle. Other linux/distro/kernel's being distributed by
MS/etc have a patch similar to this one in their tree. Its
been indicated to me that the host will eventually be fixed but
for the time being that isn't the case and anyone with a
publically available windows/arm machine can't boot fedora and
centos kernel's provided because of this.
Originally-by: Michael Kelley <mikelley(a)microsoft.com>
Tweaked to support !hyperv guest enviroments by Jeremy Linton
Signed-off-by: Jeremy Linton <jeremy.linton(a)arm.com>
diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index blahblah..blahblah 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 = generate_guest_id(0, LINUX_VERSION_CODE, 0);
@@ -63,6 +62,16 @@ 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;
+
+ if (!hyperv_initialized)
+ return 0;
+
ret = hv_common_init();
if (ret)
return ret;
@@ -74,7 +83,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 blahblah..blahblah 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
/*
* Declare calls to get and set Hyper-V VP register values on ARM64, which
@@ -41,6 +48,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 blahblah..blahblah 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;
@@ -347,6 +348,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 blahblah..blahblah 100644
--- a/drivers/clocksource/hyperv_timer.c
+++ b/drivers/clocksource/hyperv_timer.c
@@ -566,3 +566,17 @@ void __init hv_init_clocksource(void)
hv_setup_sched_clock(read_hv_sched_clock_msr);
}
EXPORT_SYMBOL_GPL(hv_init_clocksource);
+
+/* 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 blahblah..blahblah 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"
--
https://gitlab.com/cki-project/kernel-ark/-/merge_requests/1393