Author: sephe
Date: Thu Jun 23 02:37:24 2016
New Revision: 302109
URL: https://svnweb.freebsd.org/changeset/base/302109

Log:
  MFC 299927,300101,300102,300105,300107
  
  299927
      hyperv/vmbus: Use atomic_testandclear
  
      Prepare to use unsigned long for event channel bit array.
  
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D6382
  
  300101
      hyperv/vmbus: Use unsigned long for event bits.
  
      And move base channel id calculation out of inner loop.  This prepares
      for more event processing optimization.
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D6384
  
  300102
      hyperv/vmbus: Reduce the # of event loops by recording event flag count
  
      Use vmbus softc to save vmbus per-cpu data.  More stuffs will be moved
      into vmbus softc.
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D6403
  
  300105
      hyperv/vmbus: Use atomic swap and flsl to process event flags
  
      Greatly reduce the locked instructions and reduce number of inner loops.
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D6404
  
  300107
      hyperv/vmbus: Avoid two unnecessary protocol checks on isr handling path
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D6405

Added:
  stable/10/sys/dev/hyperv/vmbus/vmbus_var.h
     - copied, changed from r300102, head/sys/dev/hyperv/vmbus/vmbus_var.h
Modified:
  stable/10/sys/dev/hyperv/vmbus/hv_channel.c
  stable/10/sys/dev/hyperv/vmbus/hv_connection.c
  stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
  stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_channel.c Thu Jun 23 02:21:37 2016        
(r302108)
+++ stable/10/sys/dev/hyperv/vmbus/hv_channel.c Thu Jun 23 02:37:24 2016        
(r302109)
@@ -42,7 +42,8 @@ __FBSDID("$FreeBSD$");
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
 
-#include "hv_vmbus_priv.h"
+#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
+#include <dev/hyperv/vmbus/vmbus_var.h>
 
 static int     vmbus_channel_create_gpadl_header(
                        /* must be phys and virt contiguous*/
@@ -199,6 +200,8 @@ hv_vmbus_channel_open(
        new_channel->on_channel_callback = pfn_on_channel_callback;
        new_channel->channel_callback_context = context;
 
+       vmbus_on_channel_open(new_channel);
+
        new_channel->rxq = 
hv_vmbus_g_context.hv_event_queue[new_channel->target_cpu];
        TASK_INIT(&new_channel->channel_task, 0, VmbusProcessChannelEvent, 
new_channel);
 

Modified: stable/10/sys/dev/hyperv/vmbus/hv_connection.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_connection.c      Thu Jun 23 02:21:37 
2016        (r302108)
+++ stable/10/sys/dev/hyperv/vmbus/hv_connection.c      Thu Jun 23 02:37:24 
2016        (r302109)
@@ -36,11 +36,13 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <machine/bus.h>
+#include <machine/atomic.h>
 #include <vm/vm.h>
 #include <vm/vm_param.h>
 #include <vm/pmap.h>
 
-#include "hv_vmbus_priv.h"
+#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
+#include <dev/hyperv/vmbus/vmbus_var.h>
 
 /*
  * Globals
@@ -290,76 +292,71 @@ hv_vmbus_disconnect(void) {
        return (ret);
 }
 
-/**
- * Handler for events
- */
-void
-hv_vmbus_on_events(int cpu)
+static __inline void
+vmbus_event_flags_proc(unsigned long *event_flags, int flag_cnt)
 {
-       int bit;
-       int dword;
-       void *page_addr;
-       uint32_t* recv_interrupt_page = NULL;
-       int rel_id;
-       int maxdword;
-       hv_vmbus_synic_event_flags *event;
+       int f;
 
-       KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: "
-           "cpu out of range!"));
+       for (f = 0; f < flag_cnt; ++f) {
+               uint32_t rel_id_base;
+               unsigned long flags;
+               int bit;
 
-       page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
-       event = (hv_vmbus_synic_event_flags *)
-           page_addr + HV_VMBUS_MESSAGE_SINT;
-       if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
-           (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
-               maxdword = HV_MAX_NUM_CHANNELS_SUPPORTED >> 5;
-               /*
-                * receive size is 1/2 page and divide that by 4 bytes
-                */
-               if (synch_test_and_clear_bit(0, &event->flags32[0])) {
-                       recv_interrupt_page =
-                           hv_vmbus_g_connection.recv_interrupt_page;
-               } else {
-                       return;
+               if (event_flags[f] == 0)
+                       continue;
+
+               flags = atomic_swap_long(&event_flags[f], 0);
+               rel_id_base = f << HV_CHANNEL_ULONG_SHIFT;
+
+               while ((bit = ffsl(flags)) != 0) {
+                       struct hv_vmbus_channel *channel;
+                       uint32_t rel_id;
+
+                       --bit;  /* NOTE: ffsl is 1-based */
+                       flags &= ~(1UL << bit);
+
+                       rel_id = rel_id_base + bit;
+                       channel = hv_vmbus_g_connection.channels[rel_id];
+
+                       /* if channel is closed or closing */
+                       if (channel == NULL || channel->rxq == NULL)
+                               continue;
+
+                       if (channel->batched_reading)
+                               hv_ring_buffer_read_begin(&channel->inbound);
+                       taskqueue_enqueue(channel->rxq, &channel->channel_task);
                }
-       } else {
-               /*
-                * On Host with Win8 or above, the event page can be
-                * checked directly to get the id of the channel
-                * that has the pending interrupt.
-                */
-               maxdword = HV_EVENT_FLAGS_DWORD_COUNT;
-               recv_interrupt_page = event->flags32;
        }
+}
+
+void
+vmbus_event_proc(struct vmbus_softc *sc, int cpu)
+{
+       hv_vmbus_synic_event_flags *event;
+
+       event = ((hv_vmbus_synic_event_flags *)
+           hv_vmbus_g_context.syn_ic_event_page[cpu]) + HV_VMBUS_MESSAGE_SINT;
 
        /*
-        * Check events
+        * On Host with Win8 or above, the event page can be checked directly
+        * to get the id of the channel that has the pending interrupt.
         */
-       for (dword = 0; dword < maxdword; dword++) {
-               if (recv_interrupt_page[dword] == 0)
-                       continue;
+       vmbus_event_flags_proc(event->flagsul,
+           VMBUS_SC_PCPU_GET(sc, event_flag_cnt, cpu));
+}
 
-               for (bit = 0; bit < HV_CHANNEL_DWORD_LEN; bit++) {
-                       if (synch_test_and_clear_bit(bit,
-                           (uint32_t *)&recv_interrupt_page[dword])) {
-                               struct hv_vmbus_channel *channel;
-
-                               rel_id = (dword << 5) + bit;
-                               channel =
-                                   hv_vmbus_g_connection.channels[rel_id];
-
-                               /* if channel is closed or closing */
-                               if (channel == NULL || channel->rxq == NULL)
-                                       continue;
-
-                               if (channel->batched_reading) {
-                                       hv_ring_buffer_read_begin(
-                                           &channel->inbound);
-                               }
-                               taskqueue_enqueue(channel->rxq,
-                                   &channel->channel_task);
-                       }
-               }
+void
+vmbus_event_proc_compat(struct vmbus_softc *sc __unused, int cpu)
+{
+       hv_vmbus_synic_event_flags *event;
+
+       event = ((hv_vmbus_synic_event_flags *)
+           hv_vmbus_g_context.syn_ic_event_page[cpu]) + HV_VMBUS_MESSAGE_SINT;
+
+       if (atomic_testandclear_int(&event->flags32[0], 0)) {
+               vmbus_event_flags_proc(
+                   hv_vmbus_g_connection.recv_interrupt_page,
+                   HV_MAX_NUM_CHANNELS_SUPPORTED >> HV_CHANNEL_ULONG_SHIFT);
        }
 }
 
@@ -414,3 +411,30 @@ hv_vmbus_set_event(hv_vmbus_channel *cha
 
        return (ret);
 }
+
+void
+vmbus_on_channel_open(const struct hv_vmbus_channel *chan)
+{
+       volatile int *flag_cnt_ptr;
+       int flag_cnt;
+
+       flag_cnt = (chan->offer_msg.child_rel_id / HV_CHANNEL_ULONG_LEN) + 1;
+       flag_cnt_ptr = VMBUS_PCPU_PTR(event_flag_cnt, chan->target_cpu);
+
+       for (;;) {
+               int old_flag_cnt;
+
+               old_flag_cnt = *flag_cnt_ptr;
+               if (old_flag_cnt >= flag_cnt)
+                       break;
+               if (atomic_cmpset_int(flag_cnt_ptr, old_flag_cnt, flag_cnt)) {
+                       if (bootverbose) {
+                               printf("VMBUS: channel%u update "
+                                   "cpu%d flag_cnt to %d\n",
+                                   chan->offer_msg.child_rel_id,
+                                   chan->target_cpu, flag_cnt);
+                       }
+                       break;
+               }
+       }
+}

Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c       Thu Jun 23 
02:21:37 2016        (r302108)
+++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c       Thu Jun 23 
02:37:24 2016        (r302109)
@@ -60,11 +60,14 @@ __FBSDID("$FreeBSD$");
 #include <machine/apicvar.h>
 
 #include <dev/hyperv/include/hyperv.h>
-#include "hv_vmbus_priv.h"
+#include <dev/hyperv/vmbus/hv_vmbus_priv.h>
+#include <dev/hyperv/vmbus/vmbus_var.h>
 
 #include <contrib/dev/acpica/include/acpi.h>
 #include "acpi_if.h"
 
+struct vmbus_softc     *vmbus_sc;
+
 static device_t vmbus_devp;
 static int vmbus_inited;
 static hv_setup_args setup_args; /* only CPU 0 supported at this time */
@@ -143,6 +146,7 @@ handled:
 static inline int
 hv_vmbus_isr(struct trapframe *frame)
 {
+       struct vmbus_softc *sc = vmbus_get_softc();
        int                             cpu;
        hv_vmbus_message*               msg;
        void*                           page_addr;
@@ -154,8 +158,7 @@ hv_vmbus_isr(struct trapframe *frame)
         * before checking for messages. This is the way they do it
         * in Windows when running as a guest in Hyper-V
         */
-
-       hv_vmbus_on_events(cpu);
+       sc->vmbus_event_proc(sc, cpu);
 
        /* Check if there are actual msgs to be process */
        page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
@@ -455,6 +458,7 @@ vmbus_cpuset_setthread_task(void *xmask,
 static int
 vmbus_bus_init(void)
 {
+       struct vmbus_softc *sc;
        int i, j, n, ret;
        char buf[MAXCOMLEN + 1];
        cpuset_t cpu_mask;
@@ -463,6 +467,7 @@ vmbus_bus_init(void)
                return (0);
 
        vmbus_inited = 1;
+       sc = vmbus_get_softc();
 
        ret = hv_vmbus_init();
 
@@ -559,6 +564,12 @@ vmbus_bus_init(void)
        if (ret != 0)
                goto cleanup1;
 
+       if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 ||
+           hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)
+               sc->vmbus_event_proc = vmbus_event_proc_compat;
+       else
+               sc->vmbus_event_proc = vmbus_event_proc;
+
        hv_vmbus_request_channel_offers();
 
        vmbus_scan();
@@ -593,12 +604,26 @@ vmbus_bus_init(void)
        return (ret);
 }
 
+static void
+vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
+{
+}
+
 static int
 vmbus_attach(device_t dev)
 {
        if(bootverbose)
                device_printf(dev, "VMBUS: attach dev: %p\n", dev);
+
        vmbus_devp = dev;
+       vmbus_sc = device_get_softc(dev);
+
+       /*
+        * Event processing logic will be configured:
+        * - After the vmbus protocol version negotiation.
+        * - Before we request channel offers.
+        */
+       vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy;
 
        /* 
         * If the system has already booted and thread
@@ -616,7 +641,7 @@ vmbus_attach(device_t dev)
 static void
 vmbus_init(void)
 {
-       if (vm_guest != VM_GUEST_HV)
+       if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL)
                return;
 
        /* 
@@ -720,9 +745,11 @@ static device_method_t vmbus_methods[] =
 
        { 0, 0 } };
 
-static char driver_name[] = "vmbus";
-static driver_t vmbus_driver = { driver_name, vmbus_methods,0, };
-
+static driver_t vmbus_driver = {
+       "vmbus",
+       vmbus_methods,
+       sizeof(struct vmbus_softc)
+};
 
 devclass_t vmbus_devclass;
 

Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h      Thu Jun 23 02:21:37 
2016        (r302108)
+++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h      Thu Jun 23 02:37:24 
2016        (r302109)
@@ -57,10 +57,18 @@ typedef uint16_t hv_vmbus_status;
 #define HV_EVENT_FLAGS_COUNT        (256 * 8)
 #define HV_EVENT_FLAGS_BYTE_COUNT   (256)
 #define HV_EVENT_FLAGS_DWORD_COUNT  (256 / sizeof(uint32_t))
+#define HV_EVENT_FLAGS_ULONG_COUNT  (256 / sizeof(unsigned long))
 
 /**
  * max channel count <== event_flags_dword_count * bit_of_dword
  */
+#ifdef __LP64__
+#define HV_CHANNEL_ULONG_LEN       (64)
+#define HV_CHANNEL_ULONG_SHIFT     (6)
+#else
+#define HV_CHANNEL_ULONG_LEN       (32)
+#define HV_CHANNEL_ULONG_SHIFT     (5)
+#endif
 #define HV_CHANNEL_DWORD_LEN        (32)
 #define HV_CHANNEL_MAX_COUNT        \
        ((HV_EVENT_FLAGS_DWORD_COUNT) * HV_CHANNEL_DWORD_LEN)
@@ -575,7 +583,9 @@ typedef struct {
 typedef union {
        uint8_t         flags8[HV_EVENT_FLAGS_BYTE_COUNT];
        uint32_t        flags32[HV_EVENT_FLAGS_DWORD_COUNT];
+       unsigned long   flagsul[HV_EVENT_FLAGS_ULONG_COUNT];
 } hv_vmbus_synic_event_flags;
+CTASSERT(sizeof(hv_vmbus_synic_event_flags) == HV_EVENT_FLAGS_BYTE_COUNT);
 
 #define HV_X64_CPUID_MIN       (0x40000005)
 #define HV_X64_CPUID_MAX       (0x4000ffff)
@@ -743,7 +753,6 @@ int                 hv_vmbus_connect(void);
 int                    hv_vmbus_disconnect(void);
 int                    hv_vmbus_post_message(void *buffer, size_t buf_size);
 int                    hv_vmbus_set_event(hv_vmbus_channel *channel);
-void                   hv_vmbus_on_events(int cpu);
 
 /**
  * Event Timer interfaces

Copied and modified: stable/10/sys/dev/hyperv/vmbus/vmbus_var.h (from r300102, 
head/sys/dev/hyperv/vmbus/vmbus_var.h)
==============================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_var.h       Wed May 18 03:19:53 2016        
(r300102, copy source)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_var.h  Thu Jun 23 02:37:24 2016        
(r302109)
@@ -36,6 +36,7 @@ struct vmbus_pcpu_data {
 } __aligned(CACHE_LINE_SIZE);
 
 struct vmbus_softc {
+       void                    (*vmbus_event_proc)(struct vmbus_softc *, int);
        struct vmbus_pcpu_data  vmbus_pcpu[MAXCPU];
 };
 
@@ -47,11 +48,15 @@ vmbus_get_softc(void)
        return vmbus_sc;
 }
 
-#define VMBUS_PCPU_GET(field, cpu)     \
-       (vmbus_get_softc())->vmbus_pcpu[cpu].field
-#define VMBUS_PCPU_PTR(field, cpu)     \
-       &(vmbus_get_softc())->vmbus_pcpu[cpu].field
+#define VMBUS_SC_PCPU_GET(sc, field, cpu)      (sc)->vmbus_pcpu[(cpu)].field
+#define VMBUS_SC_PCPU_PTR(sc, field, cpu)      &(sc)->vmbus_pcpu[(cpu)].field
+#define VMBUS_PCPU_GET(field, cpu)             \
+       VMBUS_SC_PCPU_GET(vmbus_get_softc(), field, (cpu))
+#define VMBUS_PCPU_PTR(field, cpu)             \
+       VMBUS_SC_PCPU_PTR(vmbus_get_softc(), field, (cpu))
 
 void   vmbus_on_channel_open(const struct hv_vmbus_channel *);
+void   vmbus_event_proc(struct vmbus_softc *, int);
+void   vmbus_event_proc_compat(struct vmbus_softc *, int);
 
 #endif /* !_VMBUS_VAR_H_ */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to