diff options
author | Stephen Hemminger <stephen@networkplumber.org> | 2017-02-12 07:02:20 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-02-14 19:20:35 +0100 |
commit | 631e63a9f346cb657761ae22138f294718696501 (patch) | |
tree | 9d207333ca07e73282e8c7e8a4c36cf73f0d7b63 /drivers/hv/vmbus_drv.c | |
parent | vmbus: put related per-cpu variable together (diff) | |
download | linux-631e63a9f346cb657761ae22138f294718696501.tar.xz linux-631e63a9f346cb657761ae22138f294718696501.zip |
vmbus: change to per channel tasklet
Make the event handling tasklet per channel rather than per-cpu.
This allows for better fairness when getting lots of data on the same
cpu.
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hv/vmbus_drv.c')
-rw-r--r-- | drivers/hv/vmbus_drv.c | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index cf8540c1df4a..eaf1a10b0245 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -885,6 +885,56 @@ msg_handled: vmbus_signal_eom(msg, message_type); } + +/* + * Schedule all channels with events pending + */ +static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) +{ + unsigned long *recv_int_page; + u32 maxbits, relid; + + if (vmbus_proto_version < VERSION_WIN8) { + maxbits = MAX_NUM_CHANNELS_SUPPORTED; + recv_int_page = vmbus_connection.recv_int_page; + } else { + /* + * When the host is win8 and beyond, the event page + * can be directly checked to get the id of the channel + * that has the interrupt pending. + */ + void *page_addr = hv_cpu->synic_event_page; + union hv_synic_event_flags *event + = (union hv_synic_event_flags *)page_addr + + VMBUS_MESSAGE_SINT; + + maxbits = HV_EVENT_FLAGS_COUNT; + recv_int_page = event->flags; + } + + if (unlikely(!recv_int_page)) + return; + + for_each_set_bit(relid, recv_int_page, maxbits) { + struct vmbus_channel *channel; + + if (!sync_test_and_clear_bit(relid, recv_int_page)) + continue; + + /* Special case - vmbus channel protocol msg */ + if (relid == 0) + continue; + + /* Find channel based on relid */ + list_for_each_entry(channel, &hv_cpu->chan_list, percpu_list) { + if (channel->offermsg.child_relid == relid) { + tasklet_schedule(&channel->callback_event); + break; + } + } + } +} + static void vmbus_isr(void) { struct hv_per_cpu_context *hv_cpu @@ -922,8 +972,7 @@ static void vmbus_isr(void) } if (handled) - tasklet_schedule(&hv_cpu->event_dpc); - + vmbus_chan_sched(hv_cpu); page_addr = hv_cpu->synic_message_page; msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; @@ -1536,12 +1585,7 @@ static void __exit vmbus_exit(void) &hyperv_panic_block); } bus_unregister(&hv_bus); - for_each_online_cpu(cpu) { - struct hv_per_cpu_context *hv_cpu - = per_cpu_ptr(hv_context.cpu_context, cpu); - tasklet_kill(&hv_cpu->event_dpc); - } cpuhp_remove_state(hyperv_cpuhp_online); hv_synic_free(); acpi_bus_unregister_driver(&vmbus_acpi_driver); |