From: Anirudh Rayabharam (Microsoft) <[email protected]> On x86, the HYPERVISOR_CALLBACK_VECTOR is used to receive synthetic interrupts (SINTs) from the hypervisor for doorbells and intercepts. There is no such vector reserved for arm64.
On arm64, the hypervisor exposes a synthetic register that can be read to find the INTID that should be used for SINTs. This INTID is in the PPI range. To better unify the code paths, introduce mshv_sint_vector_init() that either reads the synthetic register and obtains the INTID (arm64) or just uses HYPERVISOR_CALLBACK_VECTOR as the interrupt vector (x86). Signed-off-by: Anirudh Rayabharam (Microsoft) <[email protected]> --- drivers/hv/mshv_synic.c | 112 +++++++++++++++++++++++++++++++++--- include/hyperv/hvgdk_mini.h | 2 + 2 files changed, 107 insertions(+), 7 deletions(-) diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c index 074e37c48876..7957ad0328dd 100644 --- a/drivers/hv/mshv_synic.c +++ b/drivers/hv/mshv_synic.c @@ -10,17 +10,24 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mm.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/random.h> #include <linux/cpuhotplug.h> #include <linux/reboot.h> #include <asm/mshyperv.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> #include "mshv_eventfd.h" #include "mshv.h" static int synic_cpuhp_online; static struct hv_synic_pages __percpu *synic_pages; +static int mshv_sint_vector = -1; /* hwirq for the SynIC SINTs */ +#ifndef HYPERVISOR_CALLBACK_VECTOR +static int mshv_sint_irq = -1; /* Linux IRQ for mshv_sint_vector */ +#endif static u32 synic_event_ring_get_queued_port(u32 sint_index) { @@ -456,9 +463,7 @@ static int mshv_synic_cpu_init(unsigned int cpu) union hv_synic_simp simp; union hv_synic_siefp siefp; union hv_synic_sirbp sirbp; -#ifdef HYPERVISOR_CALLBACK_VECTOR union hv_synic_sint sint; -#endif union hv_synic_scontrol sctrl; struct hv_synic_pages *spages = this_cpu_ptr(synic_pages); struct hv_message_page **msg_page = &spages->hyp_synic_message_page; @@ -501,10 +506,13 @@ static int mshv_synic_cpu_init(unsigned int cpu) hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64); -#ifdef HYPERVISOR_CALLBACK_VECTOR +#ifndef HYPERVISOR_CALLBACK_VECTOR + enable_percpu_irq(mshv_sint_irq, 0); +#endif + /* Enable intercepts */ sint.as_uint64 = 0; - sint.vector = HYPERVISOR_CALLBACK_VECTOR; + sint.vector = mshv_sint_vector; sint.masked = false; sint.auto_eoi = hv_recommend_using_aeoi(); hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX, @@ -512,13 +520,12 @@ static int mshv_synic_cpu_init(unsigned int cpu) /* Doorbell SINT */ sint.as_uint64 = 0; - sint.vector = HYPERVISOR_CALLBACK_VECTOR; + sint.vector = mshv_sint_vector; sint.masked = false; sint.as_intercept = 1; sint.auto_eoi = hv_recommend_using_aeoi(); hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX, sint.as_uint64); -#endif /* Enable global synic bit */ sctrl.as_uint64 = hv_get_non_nested_msr(HV_MSR_SCONTROL); @@ -573,6 +580,10 @@ static int mshv_synic_cpu_exit(unsigned int cpu) hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_DOORBELL_SINT_INDEX, sint.as_uint64); +#ifndef HYPERVISOR_CALLBACK_VECTOR + disable_percpu_irq(mshv_sint_irq); +#endif + /* Disable Synic's event ring page */ sirbp.as_uint64 = hv_get_non_nested_msr(HV_MSR_SIRBP); sirbp.sirbp_enabled = false; @@ -683,14 +694,98 @@ static struct notifier_block mshv_synic_reboot_nb = { .notifier_call = mshv_synic_reboot_notify, }; +#ifndef HYPERVISOR_CALLBACK_VECTOR +#ifdef CONFIG_ACPI +static long __percpu *mshv_evt; +#endif + +static irqreturn_t mshv_percpu_isr(int irq, void *dev_id) +{ + mshv_isr(); + return IRQ_HANDLED; +} + +static int __init mshv_sint_vector_init(void) +{ +#ifdef CONFIG_ACPI + int ret; + struct hv_register_assoc reg = { + .name = HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID, + }; + union hv_input_vtl input_vtl = { 0 }; + + ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF, + 1, input_vtl, ®); + if (ret || !reg.value.reg64) + return -ENODEV; + + mshv_sint_vector = reg.value.reg64; + ret = acpi_register_gsi(NULL, mshv_sint_vector, ACPI_EDGE_SENSITIVE, + ACPI_ACTIVE_HIGH); + if (ret < 0) + goto out_fail; + + mshv_sint_irq = ret; + + mshv_evt = alloc_percpu(long); + if (!mshv_evt) { + ret = -ENOMEM; + goto out_unregister; + } + + ret = request_percpu_irq(mshv_sint_irq, mshv_percpu_isr, "MSHV", + mshv_evt); + if (ret) + goto free_evt; + + return 0; + +free_evt: + free_percpu(mshv_evt); +out_unregister: + acpi_unregister_gsi(mshv_sint_vector); +out_fail: + return ret; +#else + return -ENODEV; +#endif +} + +static void mshv_sint_vector_cleanup(void) +{ +#ifdef CONFIG_ACPI + free_percpu_irq(mshv_sint_irq, mshv_evt); + free_percpu(mshv_evt); + acpi_unregister_gsi(mshv_sint_vector); +#endif +} +#else /* !HYPERVISOR_CALLBACK_VECTOR */ +static int __init mshv_sint_vector_init(void) +{ + mshv_sint_vector = HYPERVISOR_CALLBACK_VECTOR; + return 0; +} + +static void mshv_sint_vector_cleanup(void) +{ +} +#endif /* HYPERVISOR_CALLBACK_VECTOR */ + int __init mshv_synic_init(struct device *dev) { int ret = 0; + ret = mshv_sint_vector_init(); + if (ret) { + dev_err(dev, "Failed to get MSHV SINT vector: %i\n", ret); + return ret; + } + synic_pages = alloc_percpu(struct hv_synic_pages); if (!synic_pages) { dev_err(dev, "Failed to allocate percpu synic page\n"); - return -ENOMEM; + ret = -ENOMEM; + goto sint_vector_cleanup; } ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mshv_synic", @@ -713,6 +808,8 @@ int __init mshv_synic_init(struct device *dev) cpuhp_remove_state(synic_cpuhp_online); free_synic_pages: free_percpu(synic_pages); +sint_vector_cleanup: + mshv_sint_vector_cleanup(); return ret; } @@ -721,4 +818,5 @@ void mshv_synic_cleanup(void) unregister_reboot_notifier(&mshv_synic_reboot_nb); cpuhp_remove_state(synic_cpuhp_online); free_percpu(synic_pages); + mshv_sint_vector_cleanup(); } diff --git a/include/hyperv/hvgdk_mini.h b/include/hyperv/hvgdk_mini.h index 30fbbde81c5c..7676f78e0766 100644 --- a/include/hyperv/hvgdk_mini.h +++ b/include/hyperv/hvgdk_mini.h @@ -1117,6 +1117,8 @@ enum hv_register_name { HV_X64_REGISTER_MSR_MTRR_FIX4KF8000 = 0x0008007A, HV_X64_REGISTER_REG_PAGE = 0x0009001C, +#elif defined(CONFIG_ARM64) + HV_ARM64_REGISTER_SINT_RESERVED_INTERRUPT_ID = 0x00070001, #endif }; -- 2.34.1
