aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <stephen@networkplumber.org>2017-02-05 19:20:31 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-10 09:43:30 -0500
commit5c1bec61fdfcd056df909a712e2a86bbaeb0f942 (patch)
tree625f0c6561886c50334e81042e0d267390e485fc
parentbb6a4db92f8345a210b369b791e6920253b10437 (diff)
vmbus: use kernel bitops for traversing interrupt mask
Use standard kernel operations for find first set bit to traverse the channel bit array. This has added benefit of speeding up lookup on 64 bit and because it uses find first set instruction. 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>
-rw-r--r--drivers/hv/channel.c8
-rw-r--r--drivers/hv/connection.c55
-rw-r--r--drivers/hv/hyperv_vmbus.h16
-rw-r--r--drivers/hv/vmbus_drv.c4
4 files changed, 29 insertions, 54 deletions
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index be34547cdb68..a016c5c0e472 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -47,12 +47,8 @@ void vmbus_setevent(struct vmbus_channel *channel)
47 * For channels marked as in "low latency" mode 47 * For channels marked as in "low latency" mode
48 * bypass the monitor page mechanism. 48 * bypass the monitor page mechanism.
49 */ 49 */
50 if ((channel->offermsg.monitor_allocated) && 50 if (channel->offermsg.monitor_allocated && !channel->low_latency) {
51 (!channel->low_latency)) { 51 vmbus_send_interrupt(channel->offermsg.child_relid);
52 /* Each u32 represents 32 channels */
53 sync_set_bit(channel->offermsg.child_relid & 31,
54 (unsigned long *) vmbus_connection.send_int_page +
55 (channel->offermsg.child_relid >> 5));
56 52
57 /* Get the child to parent monitor page */ 53 /* Get the child to parent monitor page */
58 monitorpage = vmbus_connection.monitor_pages[1]; 54 monitorpage = vmbus_connection.monitor_pages[1];
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index 307a5a8937f6..1766ef03e78d 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -379,17 +379,11 @@ static void process_chn_event(u32 relid)
379 */ 379 */
380void vmbus_on_event(unsigned long data) 380void vmbus_on_event(unsigned long data)
381{ 381{
382 u32 dword; 382 unsigned long *recv_int_page;
383 u32 maxdword; 383 u32 maxbits, relid;
384 int bit;
385 u32 relid;
386 u32 *recv_int_page = NULL;
387 void *page_addr;
388 int cpu = smp_processor_id();
389 union hv_synic_event_flags *event;
390 384
391 if (vmbus_proto_version < VERSION_WIN8) { 385 if (vmbus_proto_version < VERSION_WIN8) {
392 maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; 386 maxbits = MAX_NUM_CHANNELS_SUPPORTED;
393 recv_int_page = vmbus_connection.recv_int_page; 387 recv_int_page = vmbus_connection.recv_int_page;
394 } else { 388 } else {
395 /* 389 /*
@@ -397,35 +391,24 @@ void vmbus_on_event(unsigned long data)
397 * can be directly checked to get the id of the channel 391 * can be directly checked to get the id of the channel
398 * that has the interrupt pending. 392 * that has the interrupt pending.
399 */ 393 */
400 maxdword = HV_EVENT_FLAGS_DWORD_COUNT; 394 int cpu = smp_processor_id();
401 page_addr = hv_context.synic_event_page[cpu]; 395 void *page_addr = hv_context.synic_event_page[cpu];
402 event = (union hv_synic_event_flags *)page_addr + 396 union hv_synic_event_flags *event
397 = (union hv_synic_event_flags *)page_addr +
403 VMBUS_MESSAGE_SINT; 398 VMBUS_MESSAGE_SINT;
404 recv_int_page = event->flags32;
405 }
406
407 399
400 maxbits = HV_EVENT_FLAGS_COUNT;
401 recv_int_page = event->flags;
402 }
408 403
409 /* Check events */ 404 if (unlikely(!recv_int_page))
410 if (!recv_int_page)
411 return; 405 return;
412 for (dword = 0; dword < maxdword; dword++) {
413 if (!recv_int_page[dword])
414 continue;
415 for (bit = 0; bit < 32; bit++) {
416 if (sync_test_and_clear_bit(bit,
417 (unsigned long *)&recv_int_page[dword])) {
418 relid = (dword << 5) + bit;
419
420 if (relid == 0)
421 /*
422 * Special case - vmbus
423 * channel protocol msg
424 */
425 continue;
426 406
407 for_each_set_bit(relid, recv_int_page, maxbits) {
408 if (sync_test_and_clear_bit(relid, recv_int_page)) {
409 /* Special case - vmbus channel protocol msg */
410 if (relid != 0)
427 process_chn_event(relid); 411 process_chn_event(relid);
428 }
429 } 412 }
430 } 413 }
431} 414}
@@ -491,12 +474,8 @@ void vmbus_set_event(struct vmbus_channel *channel)
491{ 474{
492 u32 child_relid = channel->offermsg.child_relid; 475 u32 child_relid = channel->offermsg.child_relid;
493 476
494 if (!channel->is_dedicated_interrupt) { 477 if (!channel->is_dedicated_interrupt)
495 /* Each u32 represents 32 channels */ 478 vmbus_send_interrupt(child_relid);
496 sync_set_bit(child_relid & 31,
497 (unsigned long *)vmbus_connection.send_int_page +
498 (child_relid >> 5));
499 }
500 479
501 hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL); 480 hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL);
502} 481}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 86b56b677dc3..2749a4142889 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -40,11 +40,9 @@
40 */ 40 */
41#define HV_UTIL_NEGO_TIMEOUT 55 41#define HV_UTIL_NEGO_TIMEOUT 55
42 42
43 43/* Define synthetic interrupt controller flag constants. */
44 44#define HV_EVENT_FLAGS_COUNT (256 * 8)
45 45#define HV_EVENT_FLAGS_LONG_COUNT (256 / sizeof(unsigned long))
46#define HV_EVENT_FLAGS_BYTE_COUNT (256)
47#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32))
48 46
49/* 47/*
50 * Timer configuration register. 48 * Timer configuration register.
@@ -65,8 +63,7 @@ union hv_timer_config {
65 63
66/* Define the synthetic interrupt controller event flags format. */ 64/* Define the synthetic interrupt controller event flags format. */
67union hv_synic_event_flags { 65union hv_synic_event_flags {
68 u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT]; 66 unsigned long flags[HV_EVENT_FLAGS_LONG_COUNT];
69 u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
70}; 67};
71 68
72/* Define SynIC control register. */ 69/* Define SynIC control register. */
@@ -358,6 +355,11 @@ struct vmbus_msginfo {
358 355
359extern struct vmbus_connection vmbus_connection; 356extern struct vmbus_connection vmbus_connection;
360 357
358static inline void vmbus_send_interrupt(u32 relid)
359{
360 sync_set_bit(relid, vmbus_connection.send_int_page);
361}
362
361enum vmbus_message_handler_type { 363enum vmbus_message_handler_type {
362 /* The related handler can sleep. */ 364 /* The related handler can sleep. */
363 VMHT_BLOCKING = 0, 365 VMHT_BLOCKING = 0,
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index f8ebe13cf251..c1b27026f744 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -908,10 +908,8 @@ static void vmbus_isr(void)
908 (vmbus_proto_version == VERSION_WIN7)) { 908 (vmbus_proto_version == VERSION_WIN7)) {
909 909
910 /* Since we are a child, we only need to check bit 0 */ 910 /* Since we are a child, we only need to check bit 0 */
911 if (sync_test_and_clear_bit(0, 911 if (sync_test_and_clear_bit(0, event->flags))
912 (unsigned long *) &event->flags32[0])) {
913 handled = true; 912 handled = true;
914 }
915 } else { 913 } else {
916 /* 914 /*
917 * Our host is win8 or above. The signaling mechanism 915 * Our host is win8 or above. The signaling mechanism