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-stable-10
mailing list