aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hv/vmbus_drv.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-02-23 16:40:22 -0500
committerThomas Gleixner <tglx@linutronix.de>2014-03-04 11:37:54 -0500
commit1aec169673d7db113c37367bbc371c2ba8109f06 (patch)
treef4266504ea668ed1b47300383875a96b50f58d92 /drivers/hv/vmbus_drv.c
parent99c8b79d3c165f8e2a6247c14bfa1429e7efe51f (diff)
x86: Hyperv: Cleanup the irq mess
The vmbus/hyperv interrupt handling is another complete trainwreck and probably the worst of all currently in tree. If CONFIG_HYPERV=y then the interrupt delivery to the vmbus happens via the direct HYPERVISOR_CALLBACK_VECTOR. So far so good, but: The driver requests first a normal device interrupt. The only reason to do so is to increment the interrupt stats of that device interrupt. For no reason it also installs a private flow handler. We have proper accounting mechanisms for direct vectors, but of course it's too much effort to add that 5 lines of code. Aside of that the alloc_intr_gate() is not protected against reallocation which makes module reload impossible. Solution to the problem is simple to rip out the whole mess and implement it correctly. First of all move all that code to arch/x86/kernel/cpu/mshyperv.c and merily install the HYPERVISOR_CALLBACK_VECTOR with proper reallocation protection and use the proper direct vector accounting mechanism. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: K. Y. Srinivasan <kys@microsoft.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: linuxdrivers <devel@linuxdriverproject.org> Cc: x86 <x86@kernel.org> Link: http://lkml.kernel.org/r/20140223212739.028307673@linutronix.de Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/hv/vmbus_drv.c')
-rw-r--r--drivers/hv/vmbus_drv.c39
1 files changed, 4 insertions, 35 deletions
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();