diff options
-rw-r--r-- | arch/x86/include/asm/mshyperv.h | 4 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mshyperv.c | 78 | ||||
-rw-r--r-- | drivers/hv/vmbus_drv.c | 39 |
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 | ||
7 | struct ms_hyperv_info { | 8 | struct 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 |
18 | void hyperv_vector_handler(struct pt_regs *regs); | 19 | void hyperv_vector_handler(struct pt_regs *regs); |
19 | void hv_register_vmbus_handler(int irq, irq_handler_t handler); | 20 | int hv_setup_vmbus_irq(int irq, irq_handler_t handler, void *dev_id); |
21 | void 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 @@ | |||
30 | struct ms_hyperv_info ms_hyperv; | 31 | struct ms_hyperv_info ms_hyperv; |
31 | EXPORT_SYMBOL_GPL(ms_hyperv); | 32 | EXPORT_SYMBOL_GPL(ms_hyperv); |
32 | 33 | ||
34 | #ifdef CONFIG_HYPERV | ||
35 | static irq_handler_t *vmbus_handler; | ||
36 | |||
37 | void 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 | |||
52 | int 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 | |||
64 | void 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 | } | ||
69 | EXPORT_SYMBOL_GPL(hv_setup_vmbus_irq); | ||
70 | EXPORT_SYMBOL_GPL(hv_remove_vmbus_irq); | ||
71 | #endif | ||
72 | |||
33 | static uint32_t __init ms_hyperv_platform(void) | 73 | static 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 | }; |
115 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); | 155 | EXPORT_SYMBOL(x86_hyper_ms_hyperv); |
116 | |||
117 | #if IS_ENABLED(CONFIG_HYPERV) | ||
118 | static int vmbus_irq = -1; | ||
119 | static irq_handler_t vmbus_isr; | ||
120 | |||
121 | void 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 | |||
132 | void 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 | ||
149 | void hv_register_vmbus_handler(int irq, irq_handler_t handler) | ||
150 | { | ||
151 | } | ||
152 | #endif | ||
153 | EXPORT_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 | ||
561 | static const char *driver_name = "hyperv"; | ||
562 | |||
563 | |||
564 | struct onmessage_work_context { | 560 | struct 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 | |||
685 | static 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 | ||
754 | err_alloc: | 724 | err_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 | ||
758 | err_unregister: | 728 | err_unregister: |
759 | bus_unregister(&hv_bus); | 729 | bus_unregister(&hv_bus); |
@@ -978,8 +948,7 @@ cleanup: | |||
978 | 948 | ||
979 | static void __exit vmbus_exit(void) | 949 | static 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(); |