Merge tag 'char-misc-3.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregk...
[linux-drm-fsl-dcu.git] / drivers / hv / vmbus_drv.c
index 4d6b26979fbd54e457dfbcea4bfc9a6a26ec846c..f518b8d7a5b5190eb01b741d0961f6b9fbf6cd33 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/completion.h>
 #include <linux/hyperv.h>
 #include <linux/kernel_stat.h>
+#include <linux/clockchips.h>
 #include <asm/hyperv.h>
 #include <asm/hypervisor.h>
 #include <asm/mshyperv.h>
@@ -578,6 +579,34 @@ static void vmbus_onmessage_work(struct work_struct *work)
        kfree(ctx);
 }
 
+static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
+{
+       struct clock_event_device *dev = hv_context.clk_evt[cpu];
+
+       if (dev->event_handler)
+               dev->event_handler(dev);
+
+       msg->header.message_type = HVMSG_NONE;
+
+       /*
+        * Make sure the write to MessageType (ie set to
+        * HVMSG_NONE) happens before we read the
+        * MessagePending and EOMing. Otherwise, the EOMing
+        * will not deliver any more messages since there is
+        * no empty slot
+        */
+       mb();
+
+       if (msg->header.message_flags.msg_pending) {
+               /*
+                * This will cause message queue rescan to
+                * possibly deliver another msg from the
+                * hypervisor
+                */
+               wrmsrl(HV_X64_MSR_EOM, 0);
+       }
+}
+
 static void vmbus_on_msg_dpc(unsigned long data)
 {
        int cpu = smp_processor_id();
@@ -667,8 +696,12 @@ static void vmbus_isr(void)
        msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
 
        /* Check if there are actual msgs to be processed */
-       if (msg->header.message_type != HVMSG_NONE)
-               tasklet_schedule(&msg_dpc);
+       if (msg->header.message_type != HVMSG_NONE) {
+               if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
+                       hv_process_timer_expiration(msg, cpu);
+               else
+                       tasklet_schedule(&msg_dpc);
+       }
 }
 
 /*
@@ -861,8 +894,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
                break;
 
        case ACPI_RESOURCE_TYPE_ADDRESS64:
-               hyperv_mmio.start = res->data.address64.minimum;
-               hyperv_mmio.end = res->data.address64.maximum;
+               hyperv_mmio.start = res->data.address64.address.minimum;
+               hyperv_mmio.end = res->data.address64.address.maximum;
                break;
        }