aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/mshyperv.h4
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c78
-rw-r--r--drivers/hv/vmbus_drv.c39
3 files changed, 47 insertions, 74 deletions
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index cd9c41938b8a..e98f66f35635 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -2,6 +2,7 @@
2#define _ASM_X86_MSHYPER_H 2#define _ASM_X86_MSHYPER_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/interrupt.h>
5#include <asm/hyperv.h> 6#include <asm/hyperv.h>
6 7
7struct ms_hyperv_info { 8struct ms_hyperv_info {
@@ -16,6 +17,7 @@ void hyperv_callback_vector(void);
16#define trace_hyperv_callback_vector hyperv_callback_vector 17#define trace_hyperv_callback_vector hyperv_callback_vector
17#endif 18#endif
18void hyperv_vector_handler(struct pt_regs *regs); 19void hyperv_vector_handler(struct pt_regs *regs);
19void hv_register_vmbus_handler(int irq, irq_handler_t handler); 20int hv_setup_vmbus_irq(int irq, irq_handler_t handler, void *dev_id);
21void hv_remove_vmbus_irq(int irq, void *dev_id);
20 22
21#endif 23#endif
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 9f7ca266864a..1bd316cd32c8 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>
@@ -30,6 +31,45 @@
30struct ms_hyperv_info ms_hyperv; 31struct ms_hyperv_info ms_hyperv;
31EXPORT_SYMBOL_GPL(ms_hyperv); 32EXPORT_SYMBOL_GPL(ms_hyperv);
32 33
34#ifdef CONFIG_HYPERV
35static irq_handler_t *vmbus_handler;
36
37void hyperv_vector_handler(struct pt_regs *regs)
38{
39 struct pt_regs *old_regs = set_irq_regs(regs);
40
41 irq_enter();
42 exit_idle();
43
44 inc_irq_stat(irq_hv_callback_count);
45 if (vmbus_handler)
46 vmbus_handler();
47
48 irq_exit();
49 set_irq_regs(old_regs);
50}
51
52int hv_setup_vmbus_irq(int irq, irq_handler_t *handler, void *dev_id)
53{
54 vmbus_handler = handler;
55 /*
56 * Setup the IDT for hypervisor callback. Prevent reallocation
57 * at module reload.
58 */
59 if (!test_bit(HYPERVISOR_CALLBACK_VECTOR, used_vectors))
60 alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR,
61 hyperv_callback_vector);
62}
63
64void hv_remove_vmbus_irq(unsigned int irq, void *dev_id)
65{
66 /* We have no way to deallocate the interrupt gate */
67 vmbus_handler = NULL;
68}
69EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq);
70EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq);
71#endif
72
33static uint32_t __init ms_hyperv_platform(void) 73static uint32_t __init ms_hyperv_platform(void)
34{ 74{
35 u32 eax; 75 u32 eax;
@@ -113,41 +153,3 @@ const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
113 .init_platform = ms_hyperv_init_platform, 153 .init_platform = ms_hyperv_init_platform,
114}; 154};
115EXPORT_SYMBOL(x86_hyper_ms_hyperv); 155EXPORT_SYMBOL(x86_hyper_ms_hyperv);
116
117#if IS_ENABLED(CONFIG_HYPERV)
118static int vmbus_irq = -1;
119static irq_handler_t vmbus_isr;
120
121void hv_register_vmbus_handler(int irq, irq_handler_t handler)
122{
123 /*
124 * Setup the IDT for hypervisor callback.
125 */
126 alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, hyperv_callback_vector);
127
128 vmbus_irq = irq;
129 vmbus_isr = handler;
130}
131
132void hyperv_vector_handler(struct pt_regs *regs)
133{
134 struct pt_regs *old_regs = set_irq_regs(regs);
135 struct irq_desc *desc;
136
137 irq_enter();
138 exit_idle();
139
140 desc = irq_to_desc(vmbus_irq);
141
142 if (desc)
143 generic_handle_irq_desc(vmbus_irq, desc);
144
145 irq_exit();
146 set_irq_regs(old_regs);
147}
148#else
149void hv_register_vmbus_handler(int irq, irq_handler_t handler)
150{
151}
152#endif
153EXPORT_SYMBOL_GPL(hv_register_vmbus_handler);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 077bb1bdac34..5a6909fff1c1 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -25,7 +25,6 @@
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/module.h> 26#include <linux/module.h>
27#include <linux/device.h> 27#include <linux/device.h>
28#include <linux/irq.h>
29#include <linux/interrupt.h> 28#include <linux/interrupt.h>
30#include <linux/sysctl.h> 29#include <linux/sysctl.h>
31#include <linux/slab.h> 30#include <linux/slab.h>
@@ -558,9 +557,6 @@ static struct bus_type hv_bus = {
558 .dev_groups = vmbus_groups, 557 .dev_groups = vmbus_groups,
559}; 558};
560 559
561static const char *driver_name = "hyperv";
562
563
564struct onmessage_work_context { 560struct onmessage_work_context {
565 struct work_struct work; 561 struct work_struct work;
566 struct hv_message msg; 562 struct hv_message msg;
@@ -677,19 +673,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
677} 673}
678 674
679/* 675/*
680 * vmbus interrupt flow handler:
681 * vmbus interrupts can concurrently occur on multiple CPUs and
682 * can be handled concurrently.
683 */
684
685static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
686{
687 kstat_incr_irqs_this_cpu(irq, desc);
688
689 desc->action->handler(irq, desc->action->dev_id);
690}
691
692/*
693 * vmbus_bus_init -Main vmbus driver initialization routine. 676 * vmbus_bus_init -Main vmbus driver initialization routine.
694 * 677 *
695 * Here, we 678 * Here, we
@@ -715,26 +698,13 @@ static int vmbus_bus_init(int irq)
715 if (ret) 698 if (ret)
716 goto err_cleanup; 699 goto err_cleanup;
717 700
718 ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev); 701 ret = hv_setup_vmbus_irq(irq, vmbus_isr, hv_acpi_dev);
719 702
720 if (ret != 0) { 703 if (ret != 0) {
721 pr_err("Unable to request IRQ %d\n", 704 pr_err("Unable to request IRQ %d\n", irq);
722 irq);
723 goto err_unregister; 705 goto err_unregister;
724 } 706 }
725 707
726 /*
727 * Vmbus interrupts can be handled concurrently on
728 * different CPUs. Establish an appropriate interrupt flow
729 * handler that can support this model.
730 */
731 irq_set_handler(irq, vmbus_flow_handler);
732
733 /*
734 * Register our interrupt handler.
735 */
736 hv_register_vmbus_handler(irq, vmbus_isr);
737
738 ret = hv_synic_alloc(); 708 ret = hv_synic_alloc();
739 if (ret) 709 if (ret)
740 goto err_alloc; 710 goto err_alloc;
@@ -753,7 +723,7 @@ static int vmbus_bus_init(int irq)
753 723
754err_alloc: 724err_alloc:
755 hv_synic_free(); 725 hv_synic_free();
756 free_irq(irq, hv_acpi_dev); 726 hv_remove_vmbus_irq(irq, hv_acpi_dev);
757 727
758err_unregister: 728err_unregister:
759 bus_unregister(&hv_bus); 729 bus_unregister(&hv_bus);
@@ -978,8 +948,7 @@ cleanup:
978 948
979static void __exit vmbus_exit(void) 949static void __exit vmbus_exit(void)
980{ 950{
981 951 hv_remove_vmbus_irq(irq, hv_acpi_dev);
982 free_irq(irq, hv_acpi_dev);
983 vmbus_free_channels(); 952 vmbus_free_channels();
984 bus_unregister(&hv_bus); 953 bus_unregister(&hv_bus);
985 hv_cleanup(); 954 hv_cleanup();