diff options
Diffstat (limited to 'arch/x86/kernel/cpu/mshyperv.c')
| -rw-r--r-- | arch/x86/kernel/cpu/mshyperv.c | 54 | 
1 files changed, 53 insertions, 1 deletions
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c index 0a630dd4b62..a7d26d83fb7 100644 --- a/arch/x86/kernel/cpu/mshyperv.c +++ b/arch/x86/kernel/cpu/mshyperv.c @@ -14,10 +14,15 @@  #include <linux/time.h>  #include <linux/clocksource.h>  #include <linux/module.h> +#include <linux/hardirq.h> +#include <linux/interrupt.h>  #include <asm/processor.h>  #include <asm/hypervisor.h>  #include <asm/hyperv.h>  #include <asm/mshyperv.h> +#include <asm/desc.h> +#include <asm/idle.h> +#include <asm/irq_regs.h>  struct ms_hyperv_info ms_hyperv;  EXPORT_SYMBOL_GPL(ms_hyperv); @@ -30,6 +35,13 @@ static bool __init ms_hyperv_platform(void)  	if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))  		return false; +	/* +	 * Xen emulates Hyper-V to support enlightened Windows. +	 * Check to see first if we are on a Xen Hypervisor. +	 */ +	if (xen_cpuid_base()) +		return false; +  	cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,  	      &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]); @@ -68,7 +80,14 @@ static void __init ms_hyperv_init_platform(void)  	printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n",  	       ms_hyperv.features, ms_hyperv.hints); -	clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); +	if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) +		clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); +#if IS_ENABLED(CONFIG_HYPERV) +	/* +	 * Setup the IDT for hypervisor callback. +	 */ +	alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector); +#endif  }  const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { @@ -77,3 +96,36 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {  	.init_platform		= ms_hyperv_init_platform,  };  EXPORT_SYMBOL(x86_hyper_ms_hyperv); + +#if IS_ENABLED(CONFIG_HYPERV) +static int vmbus_irq = -1; +static irq_handler_t vmbus_isr; + +void hv_register_vmbus_handler(int irq, irq_handler_t handler) +{ +	vmbus_irq = irq; +	vmbus_isr = handler; +} + +void hyperv_vector_handler(struct pt_regs *regs) +{ +	struct pt_regs *old_regs = set_irq_regs(regs); +	struct irq_desc *desc; + +	irq_enter(); +	exit_idle(); + +	desc = irq_to_desc(vmbus_irq); + +	if (desc) +		generic_handle_irq_desc(vmbus_irq, desc); + +	irq_exit(); +	set_irq_regs(old_regs); +} +#else +void hv_register_vmbus_handler(int irq, irq_handler_t handler) +{ +} +#endif +EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);  |