Date: Thu, 23 Jun 2016 02:37:24 +0000 (UTC) From: Sepherosa Ziehau <sephe@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r302109 - stable/10/sys/dev/hyperv/vmbus Message-ID: <201606230237.u5N2bO4X014467@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606230237.u5N2bO4X014467>