svn commit: r307016 - in stable/10/sys/dev/hyperv: include vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Tue Oct 11 06:04:42 UTC 2016


Author: sephe
Date: Tue Oct 11 06:04:40 2016
New Revision: 307016
URL: https://svnweb.freebsd.org/changeset/base/307016

Log:
  MFC 302543,302545,302547,302549,302554,302556,302557,302559,302606
  
  302543
      hyperv/vmbus: Use post message Hypercall APIs for channel request
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6831
  
  302545
      hyperv/vmbus: Function renaming.
  
      And pass vmbus_softc to vmbus_doattach()
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6842
  
  302547
      hyperv/vmbus: Explicitly assign channel message process array.
  
      While I'm here, remove the useless message type from message process
      array, which is not used and serves no purposes at all.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6858
  
  302549
      hyperv/vmbus: Add sysctl to expose vmbus version.
  
      Requested by:   Hongxiong Xian <v-hoxian microsoft com>
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6860
  
  302554
      hyperv/vmbus: Use post message Hypercall APIs for unload
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6861
  
  302556
      hyperv/vmbus: Create channel synchronously.
  
      The device probe/attach has been move to a different thread, so the
      reasons to create the channel asynchronously are no longer valid.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6862
  
  302557
      hyperv/vmbus: Save vmbus softc to channels.
  
      So that we don't need to access the global vmbus softc.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6863
  
  302559
      hyperv/vmbus: Embed channel detach task in channel itself.
  
      GC work queue stuffs.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6864
  
  302606
      hyperv/vmbus: Reorganize vmbus scan process.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D6875

Modified:
  stable/10/sys/dev/hyperv/include/hyperv.h
  stable/10/sys/dev/hyperv/vmbus/hv_channel.c
  stable/10/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
  stable/10/sys/dev/hyperv/vmbus/hv_connection.c
  stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
  stable/10/sys/dev/hyperv/vmbus/vmbus.c
  stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h
  stable/10/sys/dev/hyperv/vmbus/vmbus_var.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- stable/10/sys/dev/hyperv/include/hyperv.h	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/include/hyperv.h	Tue Oct 11 06:04:40 2016	(r307016)
@@ -713,6 +713,7 @@ typedef struct {
 typedef struct hv_vmbus_channel {
 	TAILQ_ENTRY(hv_vmbus_channel)	list_entry;
 	struct hv_device*		device;
+	struct vmbus_softc		*vmbus_sc;
 	hv_vmbus_channel_state		state;
 	hv_vmbus_channel_offer_channel	offer_msg;
 	/*
@@ -808,6 +809,8 @@ typedef struct hv_vmbus_channel {
 	void				*hv_chan_priv1;
 	void				*hv_chan_priv2;
 	void				*hv_chan_priv3;
+
+	struct task			ch_detach_task;
 } hv_vmbus_channel;
 
 #define HV_VMBUS_CHAN_ISPRIMARY(chan)	((chan)->primary_channel == NULL)

Modified: stable/10/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_channel.c	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/hv_channel.c	Tue Oct 11 06:04:40 2016	(r307016)
@@ -67,7 +67,7 @@ static void
 vmbus_channel_set_event(hv_vmbus_channel *channel)
 {
 	if (channel->offer_msg.monitor_allocated) {
-		struct vmbus_softc *sc = vmbus_get_softc();
+		struct vmbus_softc *sc = channel->vmbus_sc;
 		hv_vmbus_monitor_page *monitor_page;
 		uint32_t chanid = channel->offer_msg.child_rel_id;
 
@@ -205,7 +205,7 @@ hv_vmbus_channel_open(
 
 	vmbus_on_channel_open(new_channel);
 
-	new_channel->rxq = VMBUS_PCPU_GET(vmbus_get_softc(), event_tq,
+	new_channel->rxq = VMBUS_PCPU_GET(new_channel->vmbus_sc, event_tq,
 	    new_channel->target_cpu);
 	TASK_INIT(&new_channel->channel_task, 0, VmbusProcessChannelEvent, new_channel);
 

Modified: stable/10/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Tue Oct 11 06:04:40 2016	(r307016)
@@ -39,19 +39,13 @@ __FBSDID("$FreeBSD$");
 #include <dev/hyperv/vmbus/vmbus_reg.h>
 #include <dev/hyperv/vmbus/vmbus_var.h>
 
-/*
- * Internal functions
- */
+typedef void	(*vmbus_chanmsg_proc_t)
+		(struct vmbus_softc *, const struct vmbus_message *);
 
-typedef struct hv_vmbus_channel_msg_table_entry {
-	hv_vmbus_channel_msg_type    messageType;
-	void		(*messageHandler)
-			(struct vmbus_softc *sc,
-			 const struct vmbus_message *msg);
-} hv_vmbus_channel_msg_table_entry;
-
-static void	vmbus_channel_on_offer_internal(void *context);
-static void	vmbus_channel_on_offer_rescind_internal(void *context);
+static struct hv_vmbus_channel *hv_vmbus_allocate_channel(struct vmbus_softc *);
+static void	vmbus_channel_on_offer_internal(struct vmbus_softc *,
+		    const hv_vmbus_channel_offer_channel *offer);
+static void	vmbus_chan_detach_task(void *, int);
 
 static void	vmbus_channel_on_offer(struct vmbus_softc *,
 		    const struct vmbus_message *);
@@ -71,108 +65,38 @@ static void	vmbus_channel_on_version_res
 /**
  * Channel message dispatch table
  */
-static const hv_vmbus_channel_msg_table_entry
-    g_channel_message_table[HV_CHANNEL_MESSAGE_COUNT] = {
-	{ HV_CHANNEL_MESSAGE_INVALID,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_OFFER_CHANNEL,
-		vmbus_channel_on_offer },
-	{ HV_CHANNEL_MESSAGE_RESCIND_CHANNEL_OFFER,
-		vmbus_channel_on_offer_rescind },
-	{ HV_CHANNEL_MESSAGE_REQUEST_OFFERS,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_ALL_OFFERS_DELIVERED,
-		vmbus_channel_on_offers_delivered },
-	{ HV_CHANNEL_MESSAGE_OPEN_CHANNEL,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_OPEN_CHANNEL_RESULT,
-		vmbus_channel_on_open_result },
-	{ HV_CHANNEL_MESSAGE_CLOSE_CHANNEL,
-		NULL },
-	{ HV_CHANNEL_MESSAGEL_GPADL_HEADER,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_GPADL_BODY,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_GPADL_CREATED,
-		vmbus_channel_on_gpadl_created },
-	{ HV_CHANNEL_MESSAGE_GPADL_TEARDOWN,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_GPADL_TORNDOWN,
-		vmbus_channel_on_gpadl_torndown },
-	{ HV_CHANNEL_MESSAGE_REL_ID_RELEASED,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_INITIATED_CONTACT,
-		NULL },
-	{ HV_CHANNEL_MESSAGE_VERSION_RESPONSE,
-		vmbus_channel_on_version_response },
-	{ HV_CHANNEL_MESSAGE_UNLOAD,
-		NULL }
+static const vmbus_chanmsg_proc_t
+vmbus_chanmsg_process[HV_CHANNEL_MESSAGE_COUNT] = {
+	[HV_CHANNEL_MESSAGE_OFFER_CHANNEL] =
+		vmbus_channel_on_offer,
+	[HV_CHANNEL_MESSAGE_RESCIND_CHANNEL_OFFER] =
+		vmbus_channel_on_offer_rescind,
+	[HV_CHANNEL_MESSAGE_ALL_OFFERS_DELIVERED] =
+		vmbus_channel_on_offers_delivered,
+	[HV_CHANNEL_MESSAGE_OPEN_CHANNEL_RESULT] =
+		vmbus_channel_on_open_result,
+	[HV_CHANNEL_MESSAGE_GPADL_CREATED] =
+		vmbus_channel_on_gpadl_created,
+	[HV_CHANNEL_MESSAGE_GPADL_TORNDOWN] =
+		vmbus_channel_on_gpadl_torndown,
+	[HV_CHANNEL_MESSAGE_VERSION_RESPONSE] =
+		vmbus_channel_on_version_response
 };
 
-typedef struct hv_work_item {
-	struct task	work;
-	void		(*callback)(void *);
-	void*		context;
-} hv_work_item;
-
-static struct mtx	vmbus_chwait_lock;
-MTX_SYSINIT(vmbus_chwait_lk, &vmbus_chwait_lock, "vmbus primarych wait lock",
-    MTX_DEF);
-static uint32_t		vmbus_chancnt;
-static uint32_t		vmbus_devcnt;
-
-#define VMBUS_CHANCNT_DONE	0x80000000
-
-/**
- * Implementation of the work abstraction.
- */
-static void
-work_item_callback(void *work, int pending)
-{
-	struct hv_work_item *w = (struct hv_work_item *)work;
-
-	w->callback(w->context);
-
-	free(w, M_DEVBUF);
-}
-
-/**
- * @brief Create work item
- */
-static int
-hv_queue_work_item(
-	void (*callback)(void *), void *context)
-{
-	struct hv_work_item *w = malloc(sizeof(struct hv_work_item),
-					M_DEVBUF, M_NOWAIT);
-	KASSERT(w != NULL, ("Error VMBUS: Failed to allocate WorkItem\n"));
-	if (w == NULL)
-	    return (ENOMEM);
-
-	w->callback = callback;
-	w->context = context;
-
-	TASK_INIT(&w->work, 0, work_item_callback, w);
-
-	return (taskqueue_enqueue(taskqueue_thread, &w->work));
-}
-
-
 /**
  * @brief Allocate and initialize a vmbus channel object
  */
-hv_vmbus_channel*
-hv_vmbus_allocate_channel(void)
+static struct hv_vmbus_channel *
+hv_vmbus_allocate_channel(struct vmbus_softc *sc)
 {
-	hv_vmbus_channel* channel;
+	struct hv_vmbus_channel *channel;
 
-	channel = (hv_vmbus_channel*) malloc(
-					sizeof(hv_vmbus_channel),
-					M_DEVBUF,
-					M_WAITOK | M_ZERO);
+	channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO);
+	channel->vmbus_sc = sc;
 
 	mtx_init(&channel->sc_lock, "vmbus multi channel", NULL, MTX_DEF);
 	TAILQ_INIT(&channel->sc_list_anchor);
+	TASK_INIT(&channel->ch_detach_task, 0, vmbus_chan_detach_task, channel);
 
 	return (channel);
 }
@@ -195,7 +119,6 @@ static void
 vmbus_channel_process_offer(hv_vmbus_channel *new_channel)
 {
 	hv_vmbus_channel*	channel;
-	int			ret;
 	uint32_t                relid;
 
 	relid = new_channel->offer_msg.child_rel_id;
@@ -300,19 +223,8 @@ vmbus_channel_process_offer(hv_vmbus_cha
 	 * binding which eventually invokes the device driver's AddDevice()
 	 * method.
 	 */
-	ret = hv_vmbus_child_device_register(new_channel->device);
-	if (ret != 0) {
-		mtx_lock(&hv_vmbus_g_connection.channel_lock);
-		TAILQ_REMOVE(&hv_vmbus_g_connection.channel_anchor,
-		    new_channel, list_entry);
-		mtx_unlock(&hv_vmbus_g_connection.channel_lock);
-		hv_vmbus_free_vmbus_channel(new_channel);
-	}
-
-	mtx_lock(&vmbus_chwait_lock);
-	vmbus_devcnt++;
-	mtx_unlock(&vmbus_chwait_lock);
-	wakeup(&vmbus_devcnt);
+	hv_vmbus_child_device_register(new_channel->vmbus_sc,
+	    new_channel->device);
 }
 
 void
@@ -327,7 +239,7 @@ vmbus_channel_cpu_set(struct hv_vmbus_ch
 	}
 
 	chan->target_cpu = cpu;
-	chan->target_vcpu = VMBUS_PCPU_GET(vmbus_get_softc(), vcpuid, cpu);
+	chan->target_vcpu = VMBUS_PCPU_GET(chan->vmbus_sc, vcpuid, cpu);
 
 	if (bootverbose) {
 		printf("vmbus_chan%u: assigned to cpu%u [vcpu%u]\n",
@@ -396,46 +308,28 @@ vmbus_channel_select_defcpu(struct hv_vm
 /**
  * @brief Handler for channel offers from Hyper-V/Azure
  *
- * Handler for channel offers from vmbus in parent partition. We ignore
- * all offers except network and storage offers. For each network and storage
- * offers, we create a channel object and queue a work item to the channel
- * object to process the offer synchronously
+ * Handler for channel offers from vmbus in parent partition.
  */
 static void
 vmbus_channel_on_offer(struct vmbus_softc *sc, const struct vmbus_message *msg)
 {
-	const hv_vmbus_channel_msg_header *hdr =
-	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
-
 	const hv_vmbus_channel_offer_channel *offer;
-	hv_vmbus_channel_offer_channel *copied;
 
-	offer = (const hv_vmbus_channel_offer_channel *)hdr;
+	/* New channel is offered by vmbus */
+	vmbus_scan_newchan(sc);
 
-	// copy offer data
-	copied = malloc(sizeof(*copied), M_DEVBUF, M_NOWAIT);
-	if (copied == NULL) {
-		printf("fail to allocate memory\n");
-		return;
-	}
-
-	memcpy(copied, hdr, sizeof(*copied));
-	hv_queue_work_item(vmbus_channel_on_offer_internal, copied);
-
-	mtx_lock(&vmbus_chwait_lock);
-	if ((vmbus_chancnt & VMBUS_CHANCNT_DONE) == 0)
-		vmbus_chancnt++;
-	mtx_unlock(&vmbus_chwait_lock);
+	offer = (const hv_vmbus_channel_offer_channel *)msg->msg_data;
+	vmbus_channel_on_offer_internal(sc, offer);
 }
 
 static void
-vmbus_channel_on_offer_internal(void* context)
+vmbus_channel_on_offer_internal(struct vmbus_softc *sc,
+    const hv_vmbus_channel_offer_channel *offer)
 {
 	hv_vmbus_channel* new_channel;
 
-	hv_vmbus_channel_offer_channel* offer = (hv_vmbus_channel_offer_channel*)context;
 	/* Allocate the channel object and save this offer */
-	new_channel = hv_vmbus_allocate_channel();
+	new_channel = hv_vmbus_allocate_channel(sc);
 
 	/*
 	 * By default we setup state to enable batched
@@ -472,45 +366,41 @@ vmbus_channel_on_offer_internal(void* co
 	vmbus_channel_select_defcpu(new_channel);
 
 	vmbus_channel_process_offer(new_channel);
-
-	free(offer, M_DEVBUF);
 }
 
 /**
  * @brief Rescind offer handler.
  *
  * We queue a work item to process this offer
- * synchronously
+ * synchronously.
+ *
+ * XXX pretty broken; need rework.
  */
 static void
 vmbus_channel_on_offer_rescind(struct vmbus_softc *sc,
     const struct vmbus_message *msg)
 {
-	const hv_vmbus_channel_msg_header *hdr =
-	    (const hv_vmbus_channel_msg_header *)msg->msg_data;
-
 	const hv_vmbus_channel_rescind_offer *rescind;
 	hv_vmbus_channel*		channel;
 
-	rescind = (const hv_vmbus_channel_rescind_offer *)hdr;
+	rescind = (const hv_vmbus_channel_rescind_offer *)msg->msg_data;
 
 	channel = hv_vmbus_g_connection.channels[rescind->child_rel_id];
 	if (channel == NULL)
 	    return;
-
-	hv_queue_work_item(vmbus_channel_on_offer_rescind_internal, channel);
 	hv_vmbus_g_connection.channels[rescind->child_rel_id] = NULL;
+
+	taskqueue_enqueue(taskqueue_thread, &channel->ch_detach_task);
 }
 
 static void
-vmbus_channel_on_offer_rescind_internal(void *context)
+vmbus_chan_detach_task(void *xchan, int pending __unused)
 {
-	hv_vmbus_channel*               channel;
+	struct hv_vmbus_channel *chan = xchan;
 
-	channel = (hv_vmbus_channel*)context;
-	if (HV_VMBUS_CHAN_ISPRIMARY(channel)) {
+	if (HV_VMBUS_CHAN_ISPRIMARY(chan)) {
 		/* Only primary channel owns the hv_device */
-		hv_vmbus_child_device_unregister(channel->device);
+		hv_vmbus_child_device_unregister(chan->device);
 	}
 }
 
@@ -519,14 +409,12 @@ vmbus_channel_on_offer_rescind_internal(
  * @brief Invoked when all offers have been delivered.
  */
 static void
-vmbus_channel_on_offers_delivered(struct vmbus_softc *sc __unused,
+vmbus_channel_on_offers_delivered(struct vmbus_softc *sc,
     const struct vmbus_message *msg __unused)
 {
 
-	mtx_lock(&vmbus_chwait_lock);
-	vmbus_chancnt |= VMBUS_CHANCNT_DONE;
-	mtx_unlock(&vmbus_chwait_lock);
-	wakeup(&vmbus_chancnt);
+	/* No more new channels for the channel request. */
+	vmbus_scan_done(sc);
 }
 
 /**
@@ -678,36 +566,6 @@ vmbus_channel_on_version_response(struct
 }
 
 /**
- *  @brief Send a request to get all our pending offers.
- */
-int
-hv_vmbus_request_channel_offers(void)
-{
-	int				ret;
-	hv_vmbus_channel_msg_header*	msg;
-	hv_vmbus_channel_msg_info*	msg_info;
-
-	msg_info = (hv_vmbus_channel_msg_info *)
-	    malloc(sizeof(hv_vmbus_channel_msg_info)
-		    + sizeof(hv_vmbus_channel_msg_header), M_DEVBUF, M_NOWAIT);
-
-	if (msg_info == NULL) {
-	    if(bootverbose)
-		printf("Error VMBUS: malloc failed for Request Offers\n");
-	    return (ENOMEM);
-	}
-
-	msg = (hv_vmbus_channel_msg_header*) msg_info->msg;
-	msg->message_type = HV_CHANNEL_MESSAGE_REQUEST_OFFERS;
-
-	ret = hv_vmbus_post_message(msg, sizeof(hv_vmbus_channel_msg_header));
-
-	free(msg_info, M_DEVBUF);
-
-	return (ret);
-}
-
-/**
  * @brief Release channels that are unattached/unconnected (i.e., no drivers associated)
  */
 void
@@ -760,7 +618,7 @@ vmbus_select_outgoing_channel(struct hv_
 		return outgoing_channel;
 	}
 
-	cur_vcpu = VMBUS_PCPU_GET(vmbus_get_softc(), vcpuid, smp_pro_id);
+	cur_vcpu = VMBUS_PCPU_GET(primary->vmbus_sc, vcpuid, smp_pro_id);
 	
 	TAILQ_FOREACH(new_channel, &primary->sc_list_anchor, sc_list_entry) {
 		if (new_channel->state != HV_CHANNEL_OPENED_STATE){
@@ -789,21 +647,6 @@ vmbus_select_outgoing_channel(struct hv_
 	return(outgoing_channel);
 }
 
-void
-vmbus_scan(void)
-{
-	uint32_t chancnt;
-
-	mtx_lock(&vmbus_chwait_lock);
-	while ((vmbus_chancnt & VMBUS_CHANCNT_DONE) == 0)
-		mtx_sleep(&vmbus_chancnt, &vmbus_chwait_lock, 0, "waitch", 0);
-	chancnt = vmbus_chancnt & ~VMBUS_CHANCNT_DONE;
-
-	while (vmbus_devcnt != chancnt)
-		mtx_sleep(&vmbus_devcnt, &vmbus_chwait_lock, 0, "waitdev", 0);
-	mtx_unlock(&vmbus_chwait_lock);
-}
-
 struct hv_vmbus_channel **
 vmbus_get_subchan(struct hv_vmbus_channel *pri_chan, int subchan_cnt)
 {
@@ -845,20 +688,17 @@ vmbus_rel_subchan(struct hv_vmbus_channe
 void
 vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
 {
-	const hv_vmbus_channel_msg_table_entry *entry;
-	const hv_vmbus_channel_msg_header *hdr;
-	hv_vmbus_channel_msg_type msg_type;
-
-	hdr = (const hv_vmbus_channel_msg_header *)msg->msg_data;
-	msg_type = hdr->message_type;
+	vmbus_chanmsg_proc_t msg_proc;
+	uint32_t msg_type;
 
+	msg_type = ((const struct vmbus_chanmsg_hdr *)msg->msg_data)->chm_type;
 	if (msg_type >= HV_CHANNEL_MESSAGE_COUNT) {
 		device_printf(sc->vmbus_dev, "unknown message type 0x%x\n",
 		    msg_type);
 		return;
 	}
 
-	entry = &g_channel_message_table[msg_type];
-	if (entry->messageHandler)
-		entry->messageHandler(sc, msg);
+	msg_proc = vmbus_chanmsg_process[msg_type];
+	if (msg_proc != NULL)
+		msg_proc(sc, msg);
 }

Modified: stable/10/sys/dev/hyperv/vmbus/hv_connection.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_connection.c	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/hv_connection.c	Tue Oct 11 06:04:40 2016	(r307016)
@@ -95,19 +95,13 @@ hv_vmbus_connect(struct vmbus_softc *sc)
 int
 hv_vmbus_disconnect(void)
 {
-	int			 ret = 0;
-	hv_vmbus_channel_unload  msg;
-
-	msg.message_type = HV_CHANNEL_MESSAGE_UNLOAD;
-
-	ret = hv_vmbus_post_message(&msg, sizeof(hv_vmbus_channel_unload));
 
 	mtx_destroy(&hv_vmbus_g_connection.channel_msg_lock);
 
 	free(hv_vmbus_g_connection.channels, M_DEVBUF);
 	hv_vmbus_g_connection.connect_state = HV_DISCONNECTED;
 
-	return (ret);
+	return (0);
 }
 
 static __inline void
@@ -213,7 +207,7 @@ int hv_vmbus_post_message(void *buffer, 
 int
 hv_vmbus_set_event(hv_vmbus_channel *channel)
 {
-	struct vmbus_softc *sc = vmbus_get_softc();
+	struct vmbus_softc *sc = channel->vmbus_sc;
 	int ret = 0;
 	uint32_t chanid = channel->offer_msg.child_rel_id;
 
@@ -231,7 +225,7 @@ vmbus_on_channel_open(const struct hv_vm
 	int flag_cnt;
 
 	flag_cnt = (chan->offer_msg.child_rel_id / VMBUS_EVTFLAG_LEN) + 1;
-	flag_cnt_ptr = VMBUS_PCPU_PTR(vmbus_get_softc(), event_flags_cnt,
+	flag_cnt_ptr = VMBUS_PCPU_PTR(chan->vmbus_sc, event_flags_cnt,
 	    chan->target_cpu);
 
 	for (;;) {

Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Tue Oct 11 06:04:40 2016	(r307016)
@@ -395,9 +395,7 @@ void			hv_ring_buffer_read_begin(
 uint32_t		hv_ring_buffer_read_end(
 				hv_vmbus_ring_buffer_info	*ring_info);
 
-hv_vmbus_channel*	hv_vmbus_allocate_channel(void);
 void			hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel);
-int			hv_vmbus_request_channel_offers(void);
 void			hv_vmbus_release_unattached_channels(void);
 
 uint16_t		hv_vmbus_post_msg_via_msg_ipc(
@@ -413,7 +411,9 @@ struct hv_device*	hv_vmbus_child_device_
 				hv_guid			device_instance,
 				hv_vmbus_channel	*channel);
 
-int			hv_vmbus_child_device_register(
+struct vmbus_softc;
+
+void			hv_vmbus_child_device_register(struct vmbus_softc *,
 					struct hv_device *child_dev);
 int			hv_vmbus_child_device_unregister(
 					struct hv_device *child_dev);
@@ -421,13 +421,9 @@ int			hv_vmbus_child_device_unregister(
 /**
  * Connection interfaces
  */
-struct vmbus_softc;
 int			hv_vmbus_connect(struct vmbus_softc *);
 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);
 
-/* Wait for device creation */
-void			vmbus_scan(void);
-
 #endif  /* __HYPERV_PRIV_H__ */

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus.c	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus.c	Tue Oct 11 06:04:40 2016	(r307016)
@@ -98,6 +98,13 @@ struct vmbus_msghc_ctx {
 static int			vmbus_init(struct vmbus_softc *);
 static int			vmbus_init_contact(struct vmbus_softc *,
 				    uint32_t);
+static int			vmbus_req_channels(struct vmbus_softc *sc);
+static void			vmbus_uninit(struct vmbus_softc *);
+static int			vmbus_scan(struct vmbus_softc *);
+static void			vmbus_scan_wait(struct vmbus_softc *);
+static void			vmbus_scan_newdev(struct vmbus_softc *);
+
+static int			vmbus_sysctl_version(SYSCTL_HANDLER_ARGS);
 
 static struct vmbus_msghc_ctx	*vmbus_msghc_ctx_create(bus_dma_tag_t);
 static void			vmbus_msghc_ctx_destroy(
@@ -418,6 +425,131 @@ vmbus_init(struct vmbus_softc *sc)
 }
 
 static void
+vmbus_uninit(struct vmbus_softc *sc)
+{
+	struct vmbus_chanmsg_unload *req;
+	struct vmbus_msghc *mh;
+	int error;
+
+	mh = vmbus_msghc_get(sc, sizeof(*req));
+	if (mh == NULL) {
+		device_printf(sc->vmbus_dev,
+		    "can not get msg hypercall for unload\n");
+		return;
+	}
+
+	req = vmbus_msghc_dataptr(mh);
+	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_UNLOAD;
+
+	error = vmbus_msghc_exec_noresult(mh);
+	vmbus_msghc_put(sc, mh);
+
+	if (error) {
+		device_printf(sc->vmbus_dev,
+		    "unload msg hypercall failed\n");
+	}
+}
+
+static int
+vmbus_req_channels(struct vmbus_softc *sc)
+{
+	struct vmbus_chanmsg_channel_req *req;
+	struct vmbus_msghc *mh;
+	int error;
+
+	mh = vmbus_msghc_get(sc, sizeof(*req));
+	if (mh == NULL)
+		return ENXIO;
+
+	req = vmbus_msghc_dataptr(mh);
+	req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHANNEL_REQ;
+
+	error = vmbus_msghc_exec_noresult(mh);
+	vmbus_msghc_put(sc, mh);
+
+	return error;
+}
+
+void
+vmbus_scan_newchan(struct vmbus_softc *sc)
+{
+	mtx_lock(&sc->vmbus_scan_lock);
+	if ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0)
+		sc->vmbus_scan_chcnt++;
+	mtx_unlock(&sc->vmbus_scan_lock);
+}
+
+void
+vmbus_scan_done(struct vmbus_softc *sc)
+{
+	mtx_lock(&sc->vmbus_scan_lock);
+	sc->vmbus_scan_chcnt |= VMBUS_SCAN_CHCNT_DONE;
+	mtx_unlock(&sc->vmbus_scan_lock);
+	wakeup(&sc->vmbus_scan_chcnt);
+}
+
+static void
+vmbus_scan_newdev(struct vmbus_softc *sc)
+{
+	mtx_lock(&sc->vmbus_scan_lock);
+	sc->vmbus_scan_devcnt++;
+	mtx_unlock(&sc->vmbus_scan_lock);
+	wakeup(&sc->vmbus_scan_devcnt);
+}
+
+static void
+vmbus_scan_wait(struct vmbus_softc *sc)
+{
+	uint32_t chancnt;
+
+	mtx_lock(&sc->vmbus_scan_lock);
+	while ((sc->vmbus_scan_chcnt & VMBUS_SCAN_CHCNT_DONE) == 0) {
+		mtx_sleep(&sc->vmbus_scan_chcnt, &sc->vmbus_scan_lock, 0,
+		    "waitch", 0);
+	}
+	chancnt = sc->vmbus_scan_chcnt & ~VMBUS_SCAN_CHCNT_DONE;
+
+	while (sc->vmbus_scan_devcnt != chancnt) {
+		mtx_sleep(&sc->vmbus_scan_devcnt, &sc->vmbus_scan_lock, 0,
+		    "waitdev", 0);
+	}
+	mtx_unlock(&sc->vmbus_scan_lock);
+}
+
+static int
+vmbus_scan(struct vmbus_softc *sc)
+{
+	int error;
+
+	/*
+	 * Start vmbus scanning.
+	 */
+	error = vmbus_req_channels(sc);
+	if (error) {
+		device_printf(sc->vmbus_dev, "channel request failed: %d\n",
+		    error);
+		return error;
+	}
+
+	/*
+	 * Wait for all devices are added to vmbus.
+	 */
+	vmbus_scan_wait(sc);
+
+	/*
+	 * Identify, probe and attach.
+	 */
+	bus_generic_probe(sc->vmbus_dev);
+	bus_generic_attach(sc->vmbus_dev);
+
+	if (bootverbose) {
+		device_printf(sc->vmbus_dev, "device scan, probe and attach "
+		    "done\n");
+	}
+	return 0;
+}
+
+static void
 vmbus_msg_task(void *xsc, int pending __unused)
 {
 	struct vmbus_softc *sc = xsc;
@@ -972,12 +1104,13 @@ hv_vmbus_child_device_create(hv_guid typ
 	return (child_dev);
 }
 
-int
-hv_vmbus_child_device_register(struct hv_device *child_dev)
+void
+hv_vmbus_child_device_register(struct vmbus_softc *sc,
+    struct hv_device *child_dev)
 {
 	device_t child, parent;
 
-	parent = vmbus_get_device();
+	parent = sc->vmbus_dev;
 	if (bootverbose) {
 		char name[HYPERV_GUID_STRLEN];
 
@@ -989,7 +1122,8 @@ hv_vmbus_child_device_register(struct hv
 	child_dev->device = child;
 	device_set_ivars(child, child_dev);
 
-	return (0);
+	/* New device was added to vmbus */
+	vmbus_scan_newdev(sc);
 }
 
 int
@@ -1007,6 +1141,17 @@ hv_vmbus_child_device_unregister(struct 
 }
 
 static int
+vmbus_sysctl_version(SYSCTL_HANDLER_ARGS)
+{
+	char verstr[16];
+
+	snprintf(verstr, sizeof(verstr), "%u.%u",
+	    hv_vmbus_protocal_version >> 16,
+	    hv_vmbus_protocal_version & 0xffff);
+	return sysctl_handle_string(oidp, verstr, sizeof(verstr), req);
+}
+
+static int
 vmbus_probe(device_t dev)
 {
 	char *id[] = { "VMBUS", NULL };
@@ -1034,15 +1179,18 @@ vmbus_probe(device_t dev)
  * - retrieve the channel offers
  */
 static int
-vmbus_bus_init(void)
+vmbus_doattach(struct vmbus_softc *sc)
 {
-	struct vmbus_softc *sc = vmbus_get_softc();
+	struct sysctl_oid_list *child;
+	struct sysctl_ctx_list *ctx;
 	int ret;
 
 	if (sc->vmbus_flags & VMBUS_FLAG_ATTACHED)
 		return (0);
 	sc->vmbus_flags |= VMBUS_FLAG_ATTACHED;
 
+	mtx_init(&sc->vmbus_scan_lock, "vmbus scan", NULL, MTX_DEF);
+
 	/*
 	 * Create context for "post message" Hypercalls
 	 */
@@ -1092,11 +1240,15 @@ vmbus_bus_init(void)
 	else
 		sc->vmbus_event_proc = vmbus_event_proc;
 
-	hv_vmbus_request_channel_offers();
+	ret = vmbus_scan(sc);
+	if (ret != 0)
+		goto cleanup;
 
-	vmbus_scan();
-	bus_generic_attach(sc->vmbus_dev);
-	device_printf(sc->vmbus_dev, "device scan, probe and attach done\n");
+	ctx = device_get_sysctl_ctx(sc->vmbus_dev);
+	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vmbus_dev));
+	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "version",
+	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
+	    vmbus_sysctl_version, "A", "vmbus version");
 
 	return (ret);
 
@@ -1107,6 +1259,7 @@ cleanup:
 		vmbus_msghc_ctx_destroy(sc->vmbus_msg_hc);
 		sc->vmbus_msg_hc = NULL;
 	}
+	mtx_destroy(&sc->vmbus_scan_lock);
 
 	return (ret);
 }
@@ -1136,16 +1289,17 @@ vmbus_attach(device_t dev)
 	 * initialization directly.
 	 */
 	if (!cold)
-		vmbus_bus_init();
+		vmbus_doattach(vmbus_sc);
 
-	bus_generic_probe(dev);
 	return (0);
 }
 
 static void
 vmbus_sysinit(void *arg __unused)
 {
-	if (vm_guest != VM_GUEST_HV || vmbus_get_softc() == NULL)
+	struct vmbus_softc *sc = vmbus_get_softc();
+
+	if (vm_guest != VM_GUEST_HV || sc == NULL)
 		return;
 
 	/* 
@@ -1155,7 +1309,7 @@ vmbus_sysinit(void *arg __unused)
 	 * initialization directly.
 	 */
 	if (!cold) 
-		vmbus_bus_init();
+		vmbus_doattach(sc);
 }
 
 static int
@@ -1164,6 +1318,8 @@ vmbus_detach(device_t dev)
 	struct vmbus_softc *sc = device_get_softc(dev);
 
 	hv_vmbus_release_unattached_channels();
+
+	vmbus_uninit(sc);
 	hv_vmbus_disconnect();
 
 	if (sc->vmbus_flags & VMBUS_FLAG_SYNIC) {
@@ -1179,6 +1335,7 @@ vmbus_detach(device_t dev)
 		sc->vmbus_msg_hc = NULL;
 	}
 
+	mtx_destroy(&sc->vmbus_scan_lock);
 	return (0);
 }
 

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_reg.h	Tue Oct 11 06:04:40 2016	(r307016)
@@ -83,8 +83,10 @@ CTASSERT(sizeof(struct vmbus_evtflags) =
  * - Embedded in hypercall_postmsg_in.hc_data, e.g. request.
  */
 
+#define VMBUS_CHANMSG_TYPE_CHANNEL_REQ		3	/* REQ */
 #define VMBUS_CHANMSG_TYPE_INIT_CONTACT		14	/* REQ */
 #define VMBUS_CHANMSG_TYPE_VERSION_RESP		15	/* RESP */
+#define VMBUS_CHANMSG_TYPE_UNLOAD		16	/* REQ */
 
 struct vmbus_chanmsg_hdr {
 	uint32_t	chm_type;	/* VMBUS_CHANMSG_TYPE_ */
@@ -107,4 +109,14 @@ struct vmbus_chanmsg_version_resp {
 	uint8_t		chm_supp;
 } __packed;
 
+/* VMBUS_CHANMSG_TYPE_CHANNEL_REQ */
+struct vmbus_chanmsg_channel_req {
+	struct vmbus_chanmsg_hdr chm_hdr;
+} __packed;
+
+/* VMBUS_CHANMSG_TYPE_UNLOAD */
+struct vmbus_chanmsg_unload {
+	struct vmbus_chanmsg_hdr chm_hdr;
+} __packed;
+
 #endif	/* !_VMBUS_REG_H_ */

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_var.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_var.h	Tue Oct 11 05:47:52 2016	(r307015)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_var.h	Tue Oct 11 06:04:40 2016	(r307016)
@@ -83,6 +83,11 @@ struct vmbus_softc {
 	void			*vmbus_mnf1;	/* monitored by VM, unused */
 	struct hyperv_dma	vmbus_mnf1_dma;
 	struct hyperv_dma	vmbus_mnf2_dma;
+
+	struct mtx		vmbus_scan_lock;
+	uint32_t		vmbus_scan_chcnt;
+#define VMBUS_SCAN_CHCNT_DONE	0x80000000
+	uint32_t		vmbus_scan_devcnt;
 };
 
 #define VMBUS_FLAG_ATTACHED	0x0001	/* vmbus was attached */
@@ -128,4 +133,7 @@ const struct vmbus_message *vmbus_msghc_
 	    struct vmbus_msghc *);
 void	vmbus_msghc_wakeup(struct vmbus_softc *, const struct vmbus_message *);
 
+void	vmbus_scan_done(struct vmbus_softc *);
+void	vmbus_scan_newchan(struct vmbus_softc *);
+
 #endif	/* !_VMBUS_VAR_H_ */


More information about the svn-src-all mailing list