summaryrefslogtreecommitdiffstats
path: root/drivers/hv
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2014-02-23 21:40:22 +0000
committerThomas Gleixner <tglx@linutronix.de>2014-03-04 17:37:54 +0100
commit1aec169673d7db113c37367bbc371c2ba8109f06 (patch)
treef4266504ea668ed1b47300383875a96b50f58d92 /drivers/hv
parent99c8b79d3c165f8e2a6247c14bfa1429e7efe51f (diff)
downloadlinux-1aec169673d7db113c37367bbc371c2ba8109f06.tar.gz
linux-1aec169673d7db113c37367bbc371c2ba8109f06.tar.bz2
linux-1aec169673d7db113c37367bbc371c2ba8109f06.zip
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')
-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 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/sysctl.h>
#include <linux/slab.h>
@@ -558,9 +557,6 @@ static struct bus_type hv_bus = {
.dev_groups = vmbus_groups,
};
-static const char *driver_name = "hyperv";
-
-
struct onmessage_work_context {
struct work_struct work;
struct hv_message msg;
@@ -677,19 +673,6 @@ static irqreturn_t vmbus_isr(int irq, void *dev_id)
}
/*
- * vmbus interrupt flow handler:
- * vmbus interrupts can concurrently occur on multiple CPUs and
- * can be handled concurrently.
- */
-
-static void vmbus_flow_handler(unsigned int irq, struct irq_desc *desc)
-{
- kstat_incr_irqs_this_cpu(irq, desc);
-
- desc->action->handler(irq, desc->action->dev_id);
-}
-
-/*
* vmbus_bus_init -Main vmbus driver initialization routine.
*
* Here, we
@@ -715,26 +698,13 @@ static int vmbus_bus_init(int irq)
if (ret)
goto err_cleanup;
- ret = request_irq(irq, vmbus_isr, 0, driver_name, hv_acpi_dev);
+ ret = hv_setup_vmbus_irq(irq, vmbus_isr, hv_acpi_dev);
if (ret != 0) {
- pr_err("Unable to request IRQ %d\n",
- irq);
+ pr_err("Unable to request IRQ %d\n", irq);
goto err_unregister;
}
- /*
- * Vmbus interrupts can be handled concurrently on
- * different CPUs. Establish an appropriate interrupt flow
- * handler that can support this model.
- */
- irq_set_handler(irq, vmbus_flow_handler);
-
- /*
- * Register our interrupt handler.
- */
- hv_register_vmbus_handler(irq, vmbus_isr);
-
ret = hv_synic_alloc();
if (ret)
goto err_alloc;
@@ -753,7 +723,7 @@ static int vmbus_bus_init(int irq)
err_alloc:
hv_synic_free();
- free_irq(irq, hv_acpi_dev);
+ hv_remove_vmbus_irq(irq, hv_acpi_dev);
err_unregister:
bus_unregister(&hv_bus);
@@ -978,8 +948,7 @@ cleanup:
static void __exit vmbus_exit(void)
{
-
- free_irq(irq, hv_acpi_dev);
+ hv_remove_vmbus_irq(irq, hv_acpi_dev);
vmbus_free_channels();
bus_unregister(&hv_bus);
hv_cleanup();