From: Anirudh Rayabharam <[email protected]> From: Anirudh Rayabharam (Microsoft) <[email protected]>
Use the SGI allocated for MSHV as the interrupt vector to get notified of hypervisor intercepts. Currently, HYPERVISOR_CALLBACK_VECTOR is hardcoded for this. This macro exists only for x86. To make things generic, introduce an arch-specific init function mshv_arch_parent_partition_init() which, for now, is responsible for setting up the interception interrupt and writing it to the mshv_interrupt global. mshv_interrupt is then used when programming the SYNIC. Co-developed-by: Jinank Jain <[email protected]> Signed-off-by: Jinank Jain <[email protected]> Signed-off-by: Anirudh Rayabharam (Microsoft) <[email protected]> --- drivers/hv/mshv_root_main.c | 59 ++++++++++++++++++++++++++++++++++ drivers/hv/mshv_synic.c | 15 +++++---- include/asm-generic/mshyperv.h | 3 ++ 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c index bc15d6f6922f..e48a89688ecb 100644 --- a/drivers/hv/mshv_root_main.c +++ b/drivers/hv/mshv_root_main.c @@ -17,7 +17,9 @@ #include <linux/file.h> #include <linux/anon_inodes.h> #include <linux/mm.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/irq.h> #include <linux/cpuhotplug.h> #include <linux/random.h> #include <asm/mshyperv.h> @@ -75,6 +77,11 @@ static vm_fault_t mshv_vp_fault(struct vm_fault *vmf); static int mshv_init_async_handler(struct mshv_partition *partition); static void mshv_async_hvcall_handler(void *data, u64 *status); + +int mshv_interrupt = -1; +int mshv_irq = -1; +static long __percpu *mshv_evt; + static const union hv_input_vtl input_vtl_zero; static const union hv_input_vtl input_vtl_normal = { .target_vtl = HV_NORMAL_VTL, @@ -2311,6 +2318,47 @@ static void mshv_init_vmm_caps(struct device *dev) dev_dbg(dev, "vmm_caps = %#llx\n", mshv_root.vmm_caps.as_uint64[0]); } +#if IS_ENABLED(CONFIG_ARM64) +static irqreturn_t mshv_percpu_isr(int irq, void *dev_id) +{ + mshv_isr(); + add_interrupt_randomness(irq); + return IRQ_HANDLED; +} + +static int mshv_arch_parent_partition_init(struct device *dev) +{ + int ret; + + mshv_irq = mshv_get_intercept_irq(); + mshv_interrupt = irq_get_irq_data(mshv_irq)->hwirq; + + mshv_evt = alloc_percpu(long); + if (!mshv_evt) { + dev_err(dev, "Failed to allocate percpu event\n"); + return -ENOMEM; + } + + ret = request_percpu_irq(mshv_irq, mshv_percpu_isr, "MSHV", mshv_evt); + if (ret) { + dev_err(dev, "Failed to request percpu irq\n"); + goto free_percpu_buf; + } + + return ret; + +free_percpu_buf: + free_percpu(mshv_evt); + return ret; +} +#elif IS_ENABLED(CONFIG_X86_64) +static int mshv_arch_parent_partition_init(struct device *dev) +{ + mshv_interrupt = HYPERVISOR_CALLBACK_VECTOR; + return 0; +} +#endif + static int __init mshv_parent_partition_init(void) { int ret; @@ -2329,6 +2377,10 @@ static int __init mshv_parent_partition_init(void) dev = mshv_dev.this_device; + ret = mshv_arch_parent_partition_init(dev); + if (ret) + return ret; + if (version_info.build_number < MSHV_HV_MIN_VERSION || version_info.build_number > MSHV_HV_MAX_VERSION) { dev_err(dev, "Running on unvalidated Hyper-V version\n"); @@ -2396,6 +2448,13 @@ static void __exit mshv_parent_partition_exit(void) mshv_irqfd_wq_cleanup(); if (hv_root_partition()) mshv_root_partition_exit(); + if (mshv_irq >= 0) { + if (mshv_evt) { + free_percpu_irq(mshv_irq, mshv_evt); + free_percpu(mshv_evt); + mshv_evt = NULL; + } + } cpuhp_remove_state(mshv_cpuhp_online); free_percpu(mshv_root.synic_pages); } diff --git a/drivers/hv/mshv_synic.c b/drivers/hv/mshv_synic.c index f8b0337cdc82..3bdb798f8948 100644 --- a/drivers/hv/mshv_synic.c +++ b/drivers/hv/mshv_synic.c @@ -10,6 +10,7 @@ #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 <asm/mshyperv.h> @@ -451,9 +452,7 @@ int mshv_synic_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(mshv_root.synic_pages); struct hv_message_page **msg_page = &spages->hyp_synic_message_page; @@ -496,10 +495,13 @@ int mshv_synic_init(unsigned int cpu) hv_set_non_nested_msr(HV_MSR_SIRBP, sirbp.as_uint64); -#ifdef HYPERVISOR_CALLBACK_VECTOR + + if (mshv_irq > 0) + enable_percpu_irq(mshv_irq, 0); + /* Enable intercepts */ sint.as_uint64 = 0; - sint.vector = HYPERVISOR_CALLBACK_VECTOR; + sint.vector = mshv_interrupt; sint.masked = false; sint.auto_eoi = hv_recommend_using_aeoi(); hv_set_non_nested_msr(HV_MSR_SINT0 + HV_SYNIC_INTERCEPTION_SINT_INDEX, @@ -507,13 +509,12 @@ int mshv_synic_init(unsigned int cpu) /* Doorbell SINT */ sint.as_uint64 = 0; - sint.vector = HYPERVISOR_CALLBACK_VECTOR; + sint.vector = mshv_interrupt; sint.masked = false; - sint.as_intercept = 1; sint.auto_eoi = hv_recommend_using_aeoi(); + sint.as_intercept = 1; 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); diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h index ecedab554c80..8e30347f7946 100644 --- a/include/asm-generic/mshyperv.h +++ b/include/asm-generic/mshyperv.h @@ -189,6 +189,9 @@ void hv_setup_crash_handler(void (*handler)(struct pt_regs *regs)); void hv_remove_crash_handler(void); void hv_setup_mshv_handler(void (*handler)(void)); +extern int mshv_interrupt; +extern int mshv_irq; + #if IS_ENABLED(CONFIG_HYPERV) /* * Hypervisor's notion of virtual processor ID is different from -- 2.34.1
