vmbus: use kernel bitops for traversing interrupt mask
authorStephen Hemminger <stephen@networkplumber.org>
Mon, 6 Feb 2017 00:20:31 +0000 (17:20 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 10 Feb 2017 14:43:30 +0000 (15:43 +0100)
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>
drivers/hv/channel.c
drivers/hv/connection.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c

index be34547cdb681e9f2d34f05404067e1c4fdf5643..a016c5c0e472b0ed118a458b6a48296987b643a8 100644 (file)
@@ -47,12 +47,8 @@ void vmbus_setevent(struct vmbus_channel *channel)
         * For channels marked as in "low latency" mode
         * bypass the monitor page mechanism.
         */
-       if ((channel->offermsg.monitor_allocated) &&
-           (!channel->low_latency)) {
-               /* Each u32 represents 32 channels */
-               sync_set_bit(channel->offermsg.child_relid & 31,
-                       (unsigned long *) vmbus_connection.send_int_page +
-                       (channel->offermsg.child_relid >> 5));
+       if (channel->offermsg.monitor_allocated && !channel->low_latency) {
+               vmbus_send_interrupt(channel->offermsg.child_relid);
 
                /* Get the child to parent monitor page */
                monitorpage = vmbus_connection.monitor_pages[1];
index 307a5a8937f68a579d96d1ab7a7c9cba06c32cb4..1766ef03e78d0df55c02e19f147570d9718db7fb 100644 (file)
@@ -379,17 +379,11 @@ static void process_chn_event(u32 relid)
  */
 void vmbus_on_event(unsigned long data)
 {
-       u32 dword;
-       u32 maxdword;
-       int bit;
-       u32 relid;
-       u32 *recv_int_page = NULL;
-       void *page_addr;
-       int cpu = smp_processor_id();
-       union hv_synic_event_flags *event;
+       unsigned long *recv_int_page;
+       u32 maxbits, relid;
 
        if (vmbus_proto_version < VERSION_WIN8) {
-               maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
+               maxbits = MAX_NUM_CHANNELS_SUPPORTED;
                recv_int_page = vmbus_connection.recv_int_page;
        } else {
                /*
@@ -397,35 +391,24 @@ void vmbus_on_event(unsigned long data)
                 * can be directly checked to get the id of the channel
                 * that has the interrupt pending.
                 */
-               maxdword = HV_EVENT_FLAGS_DWORD_COUNT;
-               page_addr = hv_context.synic_event_page[cpu];
-               event = (union hv_synic_event_flags *)page_addr +
+               int cpu = smp_processor_id();
+               void *page_addr = hv_context.synic_event_page[cpu];
+               union hv_synic_event_flags *event
+                       = (union hv_synic_event_flags *)page_addr +
                                                 VMBUS_MESSAGE_SINT;
-               recv_int_page = event->flags32;
-       }
-
 
+               maxbits = HV_EVENT_FLAGS_COUNT;
+               recv_int_page = event->flags;
+       }
 
-       /* Check events */
-       if (!recv_int_page)
+       if (unlikely(!recv_int_page))
                return;
-       for (dword = 0; dword < maxdword; dword++) {
-               if (!recv_int_page[dword])
-                       continue;
-               for (bit = 0; bit < 32; bit++) {
-                       if (sync_test_and_clear_bit(bit,
-                               (unsigned long *)&recv_int_page[dword])) {
-                               relid = (dword << 5) + bit;
-
-                               if (relid == 0)
-                                       /*
-                                        * Special case - vmbus
-                                        * channel protocol msg
-                                        */
-                                       continue;
 
+       for_each_set_bit(relid, recv_int_page, maxbits) {
+               if (sync_test_and_clear_bit(relid, recv_int_page)) {
+                       /* Special case - vmbus channel protocol msg */
+                       if (relid != 0)
                                process_chn_event(relid);
-                       }
                }
        }
 }
@@ -491,12 +474,8 @@ void vmbus_set_event(struct vmbus_channel *channel)
 {
        u32 child_relid = channel->offermsg.child_relid;
 
-       if (!channel->is_dedicated_interrupt) {
-               /* Each u32 represents 32 channels */
-               sync_set_bit(child_relid & 31,
-                       (unsigned long *)vmbus_connection.send_int_page +
-                       (child_relid >> 5));
-       }
+       if (!channel->is_dedicated_interrupt)
+               vmbus_send_interrupt(child_relid);
 
        hv_do_hypercall(HVCALL_SIGNAL_EVENT, channel->sig_event, NULL);
 }
index 86b56b677dc39ba071da220bbe4d81baa098c91b..2749a4142889a3aa261e7fc45ded8a22126a75e5 100644 (file)
  */
 #define HV_UTIL_NEGO_TIMEOUT 55
 
-
-
-
-#define HV_EVENT_FLAGS_BYTE_COUNT      (256)
-#define HV_EVENT_FLAGS_DWORD_COUNT     (256 / sizeof(u32))
+/* Define synthetic interrupt controller flag constants. */
+#define HV_EVENT_FLAGS_COUNT           (256 * 8)
+#define HV_EVENT_FLAGS_LONG_COUNT      (256 / sizeof(unsigned long))
 
 /*
  * Timer configuration register.
@@ -65,8 +63,7 @@ union hv_timer_config {
 
 /* Define the synthetic interrupt controller event flags format. */
 union hv_synic_event_flags {
-       u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
-       u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT];
+       unsigned long flags[HV_EVENT_FLAGS_LONG_COUNT];
 };
 
 /* Define SynIC control register. */
@@ -358,6 +355,11 @@ struct vmbus_msginfo {
 
 extern struct vmbus_connection vmbus_connection;
 
+static inline void vmbus_send_interrupt(u32 relid)
+{
+       sync_set_bit(relid, vmbus_connection.send_int_page);
+}
+
 enum vmbus_message_handler_type {
        /* The related handler can sleep. */
        VMHT_BLOCKING = 0,
index f8ebe13cf25101f0362806315311237b3572cc38..c1b27026f7447a8f23b5904b43ddce46d8bf2bc6 100644 (file)
@@ -908,10 +908,8 @@ static void vmbus_isr(void)
                (vmbus_proto_version == VERSION_WIN7)) {
 
                /* Since we are a child, we only need to check bit 0 */
-               if (sync_test_and_clear_bit(0,
-                       (unsigned long *) &event->flags32[0])) {
+               if (sync_test_and_clear_bit(0, event->flags))
                        handled = true;
-               }
        } else {
                /*
                 * Our host is win8 or above. The signaling mechanism