Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[muen/linux.git] / arch / x86 / kernel / cpu / mshyperv.c
index 1afc0a4..031082c 100644 (file)
@@ -37,6 +37,7 @@ EXPORT_SYMBOL_GPL(ms_hyperv);
 
 #if IS_ENABLED(CONFIG_HYPERV)
 static void (*vmbus_handler)(void);
+static void (*hv_stimer0_handler)(void);
 static void (*hv_kexec_handler)(void);
 static void (*hv_crash_handler)(struct pt_regs *regs);
 
@@ -69,6 +70,41 @@ void hv_remove_vmbus_irq(void)
 EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
 EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
 
+/*
+ * Routines to do per-architecture handling of stimer0
+ * interrupts when in Direct Mode
+ */
+
+__visible void __irq_entry hv_stimer0_vector_handler(struct pt_regs *regs)
+{
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
+       entering_irq();
+       inc_irq_stat(hyperv_stimer0_count);
+       if (hv_stimer0_handler)
+               hv_stimer0_handler();
+       ack_APIC_irq();
+
+       exiting_irq();
+       set_irq_regs(old_regs);
+}
+
+int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void))
+{
+       *vector = HYPERV_STIMER0_VECTOR;
+       *irq = 0;   /* Unused on x86/x64 */
+       hv_stimer0_handler = handler;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(hv_setup_stimer0_irq);
+
+void hv_remove_stimer0_irq(int irq)
+{
+       /* We have no way to deallocate the interrupt gate */
+       hv_stimer0_handler = NULL;
+}
+EXPORT_SYMBOL_GPL(hv_remove_stimer0_irq);
+
 void hv_setup_kexec_handler(void (*handler)(void))
 {
        hv_kexec_handler = handler;
@@ -263,6 +299,10 @@ static void __init ms_hyperv_init_platform(void)
                alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
                                hyperv_reenlightenment_vector);
 
+       /* Setup the IDT for stimer0 */
+       if (ms_hyperv.misc_features & HV_X64_STIMER_DIRECT_MODE_AVAILABLE)
+               alloc_intr_gate(HYPERV_STIMER0_VECTOR,
+                               hv_stimer0_callback_vector);
 #endif
 }