svn commit: r302109 - stable/10/sys/dev/hyperv/vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Thu Jun 23 02:37:26 UTC 2016


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_ */


More information about the svn-src-all mailing list