Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

X86: Handle Hyper-V vmbus interrupts as special hypervisor interrupts

Starting with win8, vmbus interrupts can be delivered on any VCPU in the guest
and furthermore can be concurrently active on multiple VCPUs. Support this
interrupt delivery model by setting up a separate IDT entry for Hyper-V vmbus.
interrupts. I would like to thank Jan Beulich <JBeulich@suse.com> and
Thomas Gleixner <tglx@linutronix.de>, for their help.

In this version of the patch, based on the feedback, I have merged the IDT
vector for Xen and Hyper-V and made the necessary adjustments. Furhermore,
based on Jan's feedback I have added the necessary compilation switches.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Link: http://lkml.kernel.org/r/1359940959-32168-3-git-send-email-kys@microsoft.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

authored by

K. Y. Srinivasan and committed by
H. Peter Anvin
bc2b0331 db34bbb7

+68 -7
+2 -2
arch/x86/include/asm/irq_vectors.h
··· 109 109 110 110 #define UV_BAU_MESSAGE 0xf5 111 111 112 - /* Xen vector callback to receive events in a HVM domain */ 113 - #define XEN_HVM_EVTCHN_CALLBACK 0xf3 112 + /* Vector on which hypervisor callbacks will be delivered */ 113 + #define HYPERVISOR_CALLBACK_VECTOR 0xf3 114 114 115 115 /* 116 116 * Local APIC timer IRQ vector is on a different priority level,
+4
arch/x86/include/asm/mshyperv.h
··· 11 11 12 12 extern struct ms_hyperv_info ms_hyperv; 13 13 14 + void hyperv_callback_vector(void); 15 + void hyperv_vector_handler(struct pt_regs *regs); 16 + void hv_register_vmbus_handler(int irq, irq_handler_t handler); 17 + 14 18 #endif
+44
arch/x86/kernel/cpu/mshyperv.c
··· 14 14 #include <linux/time.h> 15 15 #include <linux/clocksource.h> 16 16 #include <linux/module.h> 17 + #include <linux/hardirq.h> 18 + #include <linux/interrupt.h> 17 19 #include <asm/processor.h> 18 20 #include <asm/hypervisor.h> 19 21 #include <asm/hyperv.h> 20 22 #include <asm/mshyperv.h> 23 + #include <asm/desc.h> 24 + #include <asm/idle.h> 25 + #include <asm/irq_regs.h> 21 26 22 27 struct ms_hyperv_info ms_hyperv; 23 28 EXPORT_SYMBOL_GPL(ms_hyperv); ··· 82 77 83 78 if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE) 84 79 clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100); 80 + #if IS_ENABLED(CONFIG_HYPERV) 81 + /* 82 + * Setup the IDT for hypervisor callback. 83 + */ 84 + alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector); 85 + #endif 85 86 } 86 87 87 88 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { ··· 96 85 .init_platform = ms_hyperv_init_platform, 97 86 }; 98 87 EXPORT_SYMBOL(x86_hyper_ms_hyperv); 88 + 89 + #if IS_ENABLED(CONFIG_HYPERV) 90 + static int vmbus_irq = -1; 91 + static irq_handler_t vmbus_isr; 92 + 93 + void hv_register_vmbus_handler(int irq, irq_handler_t handler) 94 + { 95 + vmbus_irq = irq; 96 + vmbus_isr = handler; 97 + } 98 + 99 + void hyperv_vector_handler(struct pt_regs *regs) 100 + { 101 + struct pt_regs *old_regs = set_irq_regs(regs); 102 + struct irq_desc *desc; 103 + 104 + irq_enter(); 105 + exit_idle(); 106 + 107 + desc = irq_to_desc(vmbus_irq); 108 + 109 + if (desc) 110 + generic_handle_irq_desc(vmbus_irq, desc); 111 + 112 + irq_exit(); 113 + set_irq_regs(old_regs); 114 + } 115 + #else 116 + void hv_register_vmbus_handler(int irq, irq_handler_t handler) 117 + { 118 + } 119 + #endif 120 + EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
+8 -1
arch/x86/kernel/entry_32.S
··· 1091 1091 _ASM_EXTABLE(4b,9b) 1092 1092 ENDPROC(xen_failsafe_callback) 1093 1093 1094 - BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK, 1094 + BUILD_INTERRUPT3(xen_hvm_callback_vector, HYPERVISOR_CALLBACK_VECTOR, 1095 1095 xen_evtchn_do_upcall) 1096 1096 1097 1097 #endif /* CONFIG_XEN */ 1098 + 1099 + #if IS_ENABLED(CONFIG_HYPERV) 1100 + 1101 + BUILD_INTERRUPT3(hyperv_callback_vector, HYPERVISOR_CALLBACK_VECTOR, 1102 + hyperv_vector_handler) 1103 + 1104 + #endif /* CONFIG_HYPERV */ 1098 1105 1099 1106 #ifdef CONFIG_FUNCTION_TRACER 1100 1107 #ifdef CONFIG_DYNAMIC_FTRACE
+6 -1
arch/x86/kernel/entry_64.S
··· 1454 1454 CFI_ENDPROC 1455 1455 END(xen_failsafe_callback) 1456 1456 1457 - apicinterrupt XEN_HVM_EVTCHN_CALLBACK \ 1457 + apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ 1458 1458 xen_hvm_callback_vector xen_evtchn_do_upcall 1459 1459 1460 1460 #endif /* CONFIG_XEN */ 1461 + 1462 + #if IS_ENABLED(CONFIG_HYPERV) 1463 + apicinterrupt HYPERVISOR_CALLBACK_VECTOR \ 1464 + hyperv_callback_vector hyperv_vector_handler 1465 + #endif /* CONFIG_HYPERV */ 1461 1466 1462 1467 /* 1463 1468 * Some functions should be protected against kprobes
+4 -3
drivers/xen/events.c
··· 1787 1787 int rc; 1788 1788 uint64_t callback_via; 1789 1789 if (xen_have_vector_callback) { 1790 - callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK); 1790 + callback_via = HVM_CALLBACK_VECTOR(HYPERVISOR_CALLBACK_VECTOR); 1791 1791 rc = xen_set_callback_via(callback_via); 1792 1792 if (rc) { 1793 1793 printk(KERN_ERR "Request for Xen HVM callback vector" ··· 1798 1798 printk(KERN_INFO "Xen HVM callback vector for event delivery is " 1799 1799 "enabled\n"); 1800 1800 /* in the restore case the vector has already been allocated */ 1801 - if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors)) 1802 - alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector); 1801 + if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors)) 1802 + alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, 1803 + xen_hvm_callback_vector); 1803 1804 } 1804 1805 } 1805 1806 #else