Index: sys/dev/hyperv/include/hyperv.h =================================================================== --- sys/dev/hyperv/include/hyperv.h +++ sys/dev/hyperv/include/hyperv.h @@ -760,6 +760,8 @@ struct mtx inbound_lock; + struct taskqueue * rxq; + struct task channel_task; hv_vmbus_pfn_channel_callback on_channel_callback; void* channel_callback_context; Index: sys/dev/hyperv/vmbus/hv_channel.c =================================================================== --- sys/dev/hyperv/vmbus/hv_channel.c +++ sys/dev/hyperv/vmbus/hv_channel.c @@ -114,6 +114,12 @@ new_channel->on_channel_callback = pfn_on_channel_callback; new_channel->channel_callback_context = context; + new_channel->rxq = taskqueue_create_fast("channel rxq", M_NOWAIT, + taskqueue_thread_enqueue, &new_channel->rxq); + TASK_INIT(&new_channel->channel_task, 0, VmbusProcessChannelEvent, new_channel); + + taskqueue_start_threads(&new_channel->rxq, 1, PI_NET, "channel rx thread"); + /* Allocate the ring buffer */ out = contigmalloc((send_ring_buffer_size + recv_ring_buffer_size), M_DEVBUF, M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); @@ -523,6 +529,7 @@ channel->state = HV_CHANNEL_OPEN_STATE; channel->sc_creation_callback = NULL; + taskqueue_drain(channel->rxq, &channel->channel_task); /* * Grab the lock to prevent race condition when a packet received * and unloading driver is in the process. @@ -564,6 +571,8 @@ contigfree(channel->ring_buffer_pages, channel->ring_buffer_size, M_DEVBUF); + taskqueue_free(channel->rxq); + free(info, M_DEVBUF); } Index: sys/dev/hyperv/vmbus/hv_connection.c =================================================================== --- sys/dev/hyperv/vmbus/hv_connection.c +++ sys/dev/hyperv/vmbus/hv_connection.c @@ -345,12 +345,12 @@ /** * Process a channel event notification */ -static void -VmbusProcessChannelEvent(uint32_t relid) +void +VmbusProcessChannelEvent(void* context, int pending) { void* arg; uint32_t bytes_to_read; - hv_vmbus_channel* channel; + hv_vmbus_channel* channel = (hv_vmbus_channel*)context; boolean_t is_batched_reading; /** @@ -358,8 +358,6 @@ * the channel callback to process the event */ - channel = hv_vmbus_g_connection.channels[relid]; - if (channel == NULL) { return; } @@ -411,10 +409,9 @@ * Handler for events */ void -hv_vmbus_on_events(void *arg) +hv_vmbus_on_events(int cpu) { int bit; - int cpu; int dword; void *page_addr; uint32_t* recv_interrupt_page = NULL; @@ -423,7 +420,6 @@ hv_vmbus_synic_event_flags *event; /* int maxdword = PAGE_SIZE >> 3; */ - cpu = (int)(long)arg; KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: " "cpu out of range!")); @@ -465,8 +461,10 @@ */ continue; } else { - VmbusProcessChannelEvent(rel_id); - + hv_vmbus_channel * channel = hv_vmbus_g_connection.channels[rel_id]; + if (channel->batched_reading) + hv_ring_buffer_read_begin(&channel->inbound); + taskqueue_enqueue_fast(channel->rxq, &channel->channel_task); } } } Index: sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c =================================================================== --- sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c +++ sys/dev/hyperv/vmbus/hv_vmbus_drv_freebsd.c @@ -174,7 +174,7 @@ (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) { /* Since we are a child, we only need to check bit 0 */ if (synch_test_and_clear_bit(0, &event->flags32[0])) { - swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0); + hv_vmbus_on_events(cpu); } } else { /* @@ -184,7 +184,7 @@ * Directly schedule the event software interrupt on * current cpu. */ - swi_sched(hv_vmbus_g_context.event_swintr[cpu], 0); + hv_vmbus_on_events(cpu); } /* Check if there are actual msgs to be process */ @@ -485,9 +485,7 @@ setup_args.vector = hv_vmbus_g_context.hv_cb_vector; CPU_FOREACH(j) { - hv_vmbus_g_context.hv_event_intr_event[j] = NULL; hv_vmbus_g_context.hv_msg_intr_event[j] = NULL; - hv_vmbus_g_context.event_swintr[j] = NULL; hv_vmbus_g_context.msg_swintr[j] = NULL; snprintf(buf, sizeof(buf), "cpu%d:hyperv", j); @@ -527,20 +525,6 @@ } /* - * Setup software interrupt thread and handler for - * event handling. - */ - ret = swi_add(&hv_vmbus_g_context.hv_event_intr_event[j], - "hv_event", hv_vmbus_on_events, (void *)(long)j, - SWI_CLOCK, 0, &hv_vmbus_g_context.event_swintr[j]); - if (ret) { - if(bootverbose) - printf("VMBUS: failed to setup event swi for " - "cpu %d\n", j); - goto cleanup1; - } - - /* * Prepare the per cpu msg and event pages to be called on each cpu. */ for(i = 0; i < 2; i++) { @@ -585,10 +569,7 @@ CPU_FOREACH(j) { if (hv_vmbus_g_context.msg_swintr[j] != NULL) swi_remove(hv_vmbus_g_context.msg_swintr[j]); - if (hv_vmbus_g_context.event_swintr[j] != NULL) - swi_remove(hv_vmbus_g_context.event_swintr[j]); hv_vmbus_g_context.hv_msg_intr_event[j] = NULL; - hv_vmbus_g_context.hv_event_intr_event[j] = NULL; } vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); @@ -655,10 +636,7 @@ CPU_FOREACH(i) { if (hv_vmbus_g_context.msg_swintr[i] != NULL) swi_remove(hv_vmbus_g_context.msg_swintr[i]); - if (hv_vmbus_g_context.event_swintr[i] != NULL) - swi_remove(hv_vmbus_g_context.event_swintr[i]); hv_vmbus_g_context.hv_msg_intr_event[i] = NULL; - hv_vmbus_g_context.hv_event_intr_event[i] = NULL; } vmbus_vector_free(hv_vmbus_g_context.hv_cb_vector); Index: sys/dev/hyperv/vmbus/hv_vmbus_priv.h =================================================================== --- sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -202,9 +202,7 @@ * Each cpu has its own software interrupt handler for channel * event and msg handling. */ - struct intr_event *hv_event_intr_event[MAXCPU]; struct intr_event *hv_msg_intr_event[MAXCPU]; - void *event_swintr[MAXCPU]; void *msg_swintr[MAXCPU]; /* * Host use this vector to intrrupt guest for vmbus channel @@ -685,8 +683,8 @@ 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(void *); - +void hv_vmbus_on_events(int cpu); +void VmbusProcessChannelEvent(void* channel, int pending); /* * The guest OS needs to register the guest ID with the hypervisor.