Commit bc2b0331e077f576369a2b6c75d15ed4de4ef91f

Authored by K. Y. Srinivasan
Committed by H. Peter Anvin
1 parent db34bbb767

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>

Showing 6 changed files with 68 additions and 7 deletions Side-by-side Diff

arch/x86/include/asm/irq_vectors.h
... ... @@ -109,8 +109,8 @@
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,
arch/x86/include/asm/mshyperv.h
... ... @@ -11,5 +11,9 @@
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
arch/x86/kernel/cpu/mshyperv.c
... ... @@ -14,10 +14,15 @@
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);
... ... @@ -77,6 +82,12 @@
77 82  
78 83 if (ms_hyperv.features & HV_X64_MSR_TIME_REF_COUNT_AVAILABLE)
79 84 clocksource_register_hz(&hyperv_cs, NSEC_PER_SEC/100);
  85 +#if IS_ENABLED(CONFIG_HYPERV)
  86 + /*
  87 + * Setup the IDT for hypervisor callback.
  88 + */
  89 + alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
  90 +#endif
80 91 }
81 92  
82 93 const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
... ... @@ -85,4 +96,37 @@
85 96 .init_platform = ms_hyperv_init_platform,
86 97 };
87 98 EXPORT_SYMBOL(x86_hyper_ms_hyperv);
  99 +
  100 +#if IS_ENABLED(CONFIG_HYPERV)
  101 +static int vmbus_irq = -1;
  102 +static irq_handler_t vmbus_isr;
  103 +
  104 +void hv_register_vmbus_handler(int irq, irq_handler_t handler)
  105 +{
  106 + vmbus_irq = irq;
  107 + vmbus_isr = handler;
  108 +}
  109 +
  110 +void hyperv_vector_handler(struct pt_regs *regs)
  111 +{
  112 + struct pt_regs *old_regs = set_irq_regs(regs);
  113 + struct irq_desc *desc;
  114 +
  115 + irq_enter();
  116 + exit_idle();
  117 +
  118 + desc = irq_to_desc(vmbus_irq);
  119 +
  120 + if (desc)
  121 + generic_handle_irq_desc(vmbus_irq, desc);
  122 +
  123 + irq_exit();
  124 + set_irq_regs(old_regs);
  125 +}
  126 +#else
  127 +void hv_register_vmbus_handler(int irq, irq_handler_t handler)
  128 +{
  129 +}
  130 +#endif
  131 +EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
arch/x86/kernel/entry_32.S
... ... @@ -1091,10 +1091,17 @@
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
arch/x86/kernel/entry_64.S
... ... @@ -1454,10 +1454,15 @@
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
drivers/xen/events.c
... ... @@ -1787,7 +1787,7 @@
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,8 +1798,9 @@
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