Merge tag 'hyperv-next-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyper...
[linux-2.6-block.git] / drivers / hv / vmbus_drv.c
index f6112615450adbb3a42b689597f3ce8cabc0fe87..894da5abdc550461fe0f6d9031ac1def01c81731 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/kdebug.h>
 #include <linux/efi.h>
 #include <linux/random.h>
+#include <clocksource/hyperv_timer.h>
 #include "hyperv_vmbus.h"
 
 struct vmbus_dynid {
@@ -955,17 +956,6 @@ static void vmbus_onmessage_work(struct work_struct *work)
        kfree(ctx);
 }
 
-static void hv_process_timer_expiration(struct hv_message *msg,
-                                       struct hv_per_cpu_context *hv_cpu)
-{
-       struct clock_event_device *dev = hv_cpu->clk_evt;
-
-       if (dev->event_handler)
-               dev->event_handler(dev);
-
-       vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
-}
-
 void vmbus_on_msg_dpc(unsigned long data)
 {
        struct hv_per_cpu_context *hv_cpu = (void *)data;
@@ -1159,9 +1149,10 @@ static void vmbus_isr(void)
 
        /* Check if there are actual msgs to be processed */
        if (msg->header.message_type != HVMSG_NONE) {
-               if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
-                       hv_process_timer_expiration(msg, hv_cpu);
-               else
+               if (msg->header.message_type == HVMSG_TIMER_EXPIRED) {
+                       hv_stimer0_isr();
+                       vmbus_signal_eom(msg, HVMSG_TIMER_EXPIRED);
+               } else
                        tasklet_schedule(&hv_cpu->msg_dpc);
        }
 
@@ -1263,14 +1254,19 @@ static int vmbus_bus_init(void)
        ret = hv_synic_alloc();
        if (ret)
                goto err_alloc;
+
+       ret = hv_stimer_alloc(VMBUS_MESSAGE_SINT);
+       if (ret < 0)
+               goto err_alloc;
+
        /*
-        * Initialize the per-cpu interrupt state and
-        * connect to the host.
+        * Initialize the per-cpu interrupt state and stimer state.
+        * Then connect to the host.
         */
        ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online",
                                hv_synic_init, hv_synic_cleanup);
        if (ret < 0)
-               goto err_alloc;
+               goto err_cpuhp;
        hyperv_cpuhp_online = ret;
 
        ret = vmbus_connect();
@@ -1318,6 +1314,8 @@ static int vmbus_bus_init(void)
 
 err_connect:
        cpuhp_remove_state(hyperv_cpuhp_online);
+err_cpuhp:
+       hv_stimer_free();
 err_alloc:
        hv_synic_free();
        hv_remove_vmbus_irq();
@@ -2064,7 +2062,7 @@ static struct acpi_driver vmbus_acpi_driver = {
 
 static void hv_kexec_handler(void)
 {
-       hv_synic_clockevents_cleanup();
+       hv_stimer_global_cleanup();
        vmbus_initiate_unload(false);
        vmbus_connection.conn_state = DISCONNECTED;
        /* Make sure conn_state is set as hv_synic_cleanup checks for it */
@@ -2075,6 +2073,8 @@ static void hv_kexec_handler(void)
 
 static void hv_crash_handler(struct pt_regs *regs)
 {
+       int cpu;
+
        vmbus_initiate_unload(true);
        /*
         * In crash handler we can't schedule synic cleanup for all CPUs,
@@ -2082,7 +2082,9 @@ static void hv_crash_handler(struct pt_regs *regs)
         * for kdump.
         */
        vmbus_connection.conn_state = DISCONNECTED;
-       hv_synic_cleanup(smp_processor_id());
+       cpu = smp_processor_id();
+       hv_stimer_cleanup(cpu);
+       hv_synic_cleanup(cpu);
        hyperv_cleanup();
 };
 
@@ -2131,7 +2133,7 @@ static void __exit vmbus_exit(void)
        hv_remove_kexec_handler();
        hv_remove_crash_handler();
        vmbus_connection.conn_state = DISCONNECTED;
-       hv_synic_clockevents_cleanup();
+       hv_stimer_global_cleanup();
        vmbus_disconnect();
        hv_remove_vmbus_irq();
        for_each_online_cpu(cpu) {