Drivers: hv: vmbus: Support handling messages on multiple CPUs
authorK. Y. Srinivasan <kys@microsoft.com>
Fri, 26 Feb 2016 23:13:21 +0000 (15:13 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 2 Mar 2016 00:57:20 +0000 (16:57 -0800)
Starting with Windows 2012 R2, message inteerupts can be delivered
on any VCPU in the guest. Support this functionality.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/hv/hv.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c

index ccb335f57c8823bdadd79bc03e60140c5d07c9ba..a1c086ba3b9a0736c522d648092d04d4ac92a3c7 100644 (file)
@@ -204,6 +204,8 @@ int hv_init(void)
               sizeof(int) * NR_CPUS);
        memset(hv_context.event_dpc, 0,
               sizeof(void *) * NR_CPUS);
+       memset(hv_context.msg_dpc, 0,
+              sizeof(void *) * NR_CPUS);
        memset(hv_context.clk_evt, 0,
               sizeof(void *) * NR_CPUS);
 
@@ -415,6 +417,13 @@ int hv_synic_alloc(void)
                }
                tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
 
+               hv_context.msg_dpc[cpu] = kmalloc(size, GFP_ATOMIC);
+               if (hv_context.msg_dpc[cpu] == NULL) {
+                       pr_err("Unable to allocate event dpc\n");
+                       goto err;
+               }
+               tasklet_init(hv_context.msg_dpc[cpu], vmbus_on_msg_dpc, cpu);
+
                hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC);
                if (hv_context.clk_evt[cpu] == NULL) {
                        pr_err("Unable to allocate clock event device\n");
@@ -456,6 +465,7 @@ err:
 static void hv_synic_free_cpu(int cpu)
 {
        kfree(hv_context.event_dpc[cpu]);
+       kfree(hv_context.msg_dpc[cpu]);
        kfree(hv_context.clk_evt[cpu]);
        if (hv_context.synic_event_page[cpu])
                free_page((unsigned long)hv_context.synic_event_page[cpu]);
index cada56a2daa08b426669a22c0ca58390bbf6c109..a64b17661d178577a5d3805cd386f24bfd78a91f 100644 (file)
@@ -449,10 +449,11 @@ struct hv_context {
        u32 vp_index[NR_CPUS];
        /*
         * Starting with win8, we can take channel interrupts on any CPU;
-        * we will manage the tasklet that handles events on a per CPU
+        * we will manage the tasklet that handles events messages on a per CPU
         * basis.
         */
        struct tasklet_struct *event_dpc[NR_CPUS];
+       struct tasklet_struct *msg_dpc[NR_CPUS];
        /*
         * To optimize the mapping of relid to channel, maintain
         * per-cpu list of the channels based on their CPU affinity.
@@ -675,6 +676,7 @@ int vmbus_post_msg(void *buffer, size_t buflen);
 void vmbus_set_event(struct vmbus_channel *channel);
 
 void vmbus_on_event(unsigned long data);
+void vmbus_on_msg_dpc(unsigned long data);
 
 int hv_kvp_init(struct hv_util_service *);
 void hv_kvp_deinit(void);
index 6cd12f108a3237d9487bee95d6303fda16676a90..64713ff47e36c73e70d429dd6650d27d3e2e1d97 100644 (file)
@@ -45,7 +45,6 @@
 
 static struct acpi_device  *hv_acpi_dev;
 
-static struct tasklet_struct msg_dpc;
 static struct completion probe_event;
 
 
@@ -712,7 +711,7 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
        vmbus_signal_eom(msg);
 }
 
-static void vmbus_on_msg_dpc(unsigned long data)
+void vmbus_on_msg_dpc(unsigned long data)
 {
        int cpu = smp_processor_id();
        void *page_addr = hv_context.synic_message_page[cpu];
@@ -800,7 +799,7 @@ static void vmbus_isr(void)
                if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
                        hv_process_timer_expiration(msg, cpu);
                else
-                       tasklet_schedule(&msg_dpc);
+                       tasklet_schedule(hv_context.msg_dpc[cpu]);
        }
 }
 
@@ -824,8 +823,6 @@ static int vmbus_bus_init(void)
                return ret;
        }
 
-       tasklet_init(&msg_dpc, vmbus_on_msg_dpc, 0);
-
        ret = bus_register(&hv_bus);
        if (ret)
                goto err_cleanup;
@@ -1321,7 +1318,8 @@ static void __exit vmbus_exit(void)
        hv_synic_clockevents_cleanup();
        vmbus_disconnect();
        hv_remove_vmbus_irq();
-       tasklet_kill(&msg_dpc);
+       for_each_online_cpu(cpu)
+               tasklet_kill(hv_context.msg_dpc[cpu]);
        vmbus_free_channels();
        if (ms_hyperv.misc_features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
                unregister_die_notifier(&hyperv_die_block);