Skip to content

Commit

Permalink
arm64: hyperv: Enable Hyper-V synthetic clocks/timers
Browse files Browse the repository at this point in the history
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
 245b993 ("clocksource: hyper-v: unexport __init-annotated
 hv_init_clocksource()")
Signed-off-by: Tyler Hicks <tyhicks@linux.microsoft.com>
  • Loading branch information
kelleymh authored and tyhicks committed Jul 27, 2022
1 parent ee03900 commit 59db35e
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 6 deletions.
15 changes: 10 additions & 5 deletions arch/arm64/hyperv/mshyperv.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,22 @@

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
* a non-Hyper-V environment, including on DT instead of ACPI.
* 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);
Expand Down Expand Up @@ -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;
Expand All @@ -74,7 +80,6 @@ static int __init hyperv_init(void)
return ret;
}

hyperv_initialized = true;
return 0;
}

Expand Down
18 changes: 18 additions & 0 deletions arch/arm64/include/asm/mshyperv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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( \
Expand Down
4 changes: 4 additions & 0 deletions arch/arm64/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
14 changes: 14 additions & 0 deletions drivers/clocksource/hyperv_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,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);
2 changes: 1 addition & 1 deletion drivers/hv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ config HYPERV
system.

config HYPERV_TIMER
def_bool HYPERV && X86
def_bool HYPERV

config HYPERV_UTILS
tristate "Microsoft Hyper-V Utilities driver"
Expand Down

0 comments on commit 59db35e

Please sign in to comment.