[PATCH 7/8] Drivers: hv: vmbus: Support handling messages on multiple CPUs

From: K. Y. Srinivasan
Date: Fri Feb 26 2016 - 16:36:12 EST


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@xxxxxxxxxxxxx>
---
drivers/hv/hv.c | 10 ++++++++++
drivers/hv/hyperv_vmbus.h | 4 +++-
drivers/hv/vmbus_drv.c | 10 ++++------
3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index ccb335f..a1c086b 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -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]);
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index cada56a..a64b176 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -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);
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 6cd12f1..64713ff 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -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);
--
1.7.4.1