aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/cpu/mshyperv.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/mshyperv.c')
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c78
1 files changed, 40 insertions, 38 deletions
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 832d05a914ba..76f98fe5b35c 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -17,6 +17,7 @@
17#include <linux/hardirq.h> 17#include <linux/hardirq.h>
18#include <linux/efi.h> 18#include <linux/efi.h>
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/irq.h>
20#include <asm/processor.h> 21#include <asm/processor.h>
21#include <asm/hypervisor.h> 22#include <asm/hypervisor.h>
22#include <asm/hyperv.h> 23#include <asm/hyperv.h>
@@ -31,6 +32,45 @@
31struct ms_hyperv_info ms_hyperv; 32struct ms_hyperv_info ms_hyperv;
32EXPORT_SYMBOL_GPL(ms_hyperv); 33EXPORT_SYMBOL_GPL(ms_hyperv);
33 34
35#if IS_ENABLED(CONFIG_HYPERV)
36static void (*vmbus_handler)(void);
37
38void hyperv_vector_handler(struct pt_regs *regs)
39{
40 struct pt_regs *old_regs = set_irq_regs(regs);
41
42 irq_enter();
43 exit_idle();
44
45 inc_irq_stat(irq_hv_callback_count);
46 if (vmbus_handler)
47 vmbus_handler();
48
49 irq_exit();
50 set_irq_regs(old_regs);
51}
52
53void hv_setup_vmbus_irq(void (*handler)(void))
54{
55 vmbus_handler = handler;
56 /*
57 * Setup the IDT for hypervisor callback. Prevent reallocation
58 * at module reload.
59 */
60 if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
61 alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
62 hyperv_callback_vector);
63}
64
65void hv_remove_vmbus_irq(void)
66{
67 /* We have no way to deallocate the interrupt gate */
68 vmbus_handler = NULL;
69}
70EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
71EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
72#endif
73
34static uint32_t __init ms_hyperv_platform(void) 74static uint32_t __init ms_hyperv_platform(void)
35{ 75{
36 u32 eax; 76 u32 eax;
@@ -119,41 +159,3 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
119 .init_platform = ms_hyperv_init_platform, 159 .init_platform = ms_hyperv_init_platform,
120}; 160};
121EXPORT_SYMBOL(x86_hyper_ms_hyperv); 161EXPORT_SYMBOL(x86_hyper_ms_hyperv);
122
123#if IS_ENABLED(CONFIG_HYPERV)
124static int vmbus_irq = -1;
125static irq_handler_t vmbus_isr;
126
127void hv_register_vmbus_handler(int irq, irq_handler_t handler)
128{
129 /*
130 * Setup the IDT for hypervisor callback.
131 */
132 alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
133
134 vmbus_irq = irq;
135 vmbus_isr = handler;
136}
137
138void hyperv_vector_handler(struct pt_regs *regs)
139{
140 struct pt_regs *old_regs = set_irq_regs(regs);
141 struct irq_desc *desc;
142
143 irq_enter();
144 exit_idle();
145
146 desc = irq_to_desc(vmbus_irq);
147
148 if (desc)
149 generic_handle_irq_desc(vmbus_irq, desc);
150
151 irq_exit();
152 set_irq_regs(old_regs);
153}
154#else
155void hv_register_vmbus_handler(int irq, irq_handler_t handler)
156{
157}
158#endif
159EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);