Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Oct 2016 08:14:11 +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: r307027 - in stable/10/sys/dev/hyperv: include netvsc vmbus
Message-ID:  <201610110814.u9B8EBnw026673@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Tue Oct 11 08:14:11 2016
New Revision: 307027
URL: https://svnweb.freebsd.org/changeset/base/307027

Log:
  MFC 302808-302815
  
  302808
      hyperv/vmbus: Alloc/Free monitor param in vmbus channel alloc/free.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7101
  
  302809
      hyperv/vmbus: Move device register and channel free to the caller.
  
      This paves the way for more cleanup/disentangle.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7102
  
  302810
      hyperv/vmbus: Move new channel scan notification to device register
  
      And nuke now unnecessary function indirection.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7103
  
  302811
      hyperv/vmbus: Cleanup vmbus_chan_msgproc_choffer
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7104
  
  302812
      hyperv/vmbus: Nuke the channel open state.
  
      Channel is either opened or not-opened.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7105
  
  302813
      hyperv/vmbus: Cleanup vmbus_chan_add()
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7106
  
  302814
      hyperv/vmbus: Use sub-channel index to detect primary channel
  
      In case that VMBUS_CHAN_ISPRIMARY is needed in the early place of
      channel setup.
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7108
  
  302815
      hyperv/vmbus: Only add primary channels to vmbus channel list
  
      - Make the vmbus_chan_add more straightforward.
      - Partially fix the hv_vmbus_release_unattached_channels().
  
      Sponsored by:   Microsoft OSTC
      Differential Revision:  https://reviews.freebsd.org/D7109

Modified:
  stable/10/sys/dev/hyperv/include/hyperv.h
  stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
  stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  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_vmbus_priv.h
  stable/10/sys/dev/hyperv/vmbus/vmbus.c
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 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/include/hyperv.h	Tue Oct 11 08:14:11 2016	(r307027)
@@ -244,18 +244,9 @@ typedef struct {
 
 typedef void (*hv_vmbus_pfn_channel_callback)(void *context);
 
-typedef enum {
-	HV_CHANNEL_OFFER_STATE,
-	HV_CHANNEL_OPENING_STATE,
-	HV_CHANNEL_OPEN_STATE,
-	HV_CHANNEL_OPENED_STATE,
-	HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE,
-} hv_vmbus_channel_state;
-
 typedef struct hv_vmbus_channel {
 	device_t			ch_dev;
 	struct vmbus_softc		*vmbus_sc;
-	hv_vmbus_channel_state		state;
 	uint32_t			ch_flags;	/* VMBUS_CHAN_FLAG_ */
 	uint32_t			ch_id;		/* channel id */
 
@@ -337,14 +328,15 @@ typedef struct hv_vmbus_channel {
 	struct task			ch_detach_task;
 	TAILQ_ENTRY(hv_vmbus_channel)	ch_link;
 	uint32_t			ch_subidx;	/* subchan index */
-
+	volatile uint32_t		ch_stflags;	/* atomic-op */
+							/* VMBUS_CHAN_ST_ */
 	struct hyperv_guid		ch_guid_type;
 	struct hyperv_guid		ch_guid_inst;
 
 	struct sysctl_ctx_list		ch_sysctl_ctx;
 } hv_vmbus_channel;
 
-#define HV_VMBUS_CHAN_ISPRIMARY(chan)	((chan)->primary_channel == NULL)
+#define VMBUS_CHAN_ISPRIMARY(chan)	((chan)->ch_subidx == 0)
 
 #define VMBUS_CHAN_FLAG_HASMNF		0x0001
 /*
@@ -357,6 +349,9 @@ typedef struct hv_vmbus_channel {
  */
 #define VMBUS_CHAN_FLAG_BATCHREAD	0x0002
 
+#define VMBUS_CHAN_ST_OPENED_SHIFT	0
+#define VMBUS_CHAN_ST_OPENED		(1 << VMBUS_CHAN_ST_OPENED_SHIFT)
+
 static inline void
 hv_set_channel_read_state(hv_vmbus_channel* channel, boolean_t on)
 {

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c	Tue Oct 11 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c	Tue Oct 11 08:14:11 2016	(r307027)
@@ -718,11 +718,6 @@ hv_nv_on_device_remove(struct hn_softc *
 
 	/* Now, we can close the channel safely */
 
-	if (!destroy_channel) {
-		sc->hn_prichan->state =
-		    HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE;
-	}
-
 	free(sc->hn_prichan->hv_chan_rdbuf, M_NETVSC);
 	hv_vmbus_channel_close(sc->hn_prichan);
 

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Tue Oct 11 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Tue Oct 11 08:14:11 2016	(r307027)
@@ -3013,7 +3013,7 @@ static void
 hn_subchan_attach(struct hn_softc *sc, struct hv_vmbus_channel *chan)
 {
 
-	KASSERT(!HV_VMBUS_CHAN_ISPRIMARY(chan),
+	KASSERT(!VMBUS_CHAN_ISPRIMARY(chan),
 	    ("subchannel callback on primary channel"));
 	KASSERT(chan->ch_subidx > 0,
 	    ("invalid channel subidx %u",

Modified: stable/10/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_channel.c	Tue Oct 11 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/vmbus/hv_channel.c	Tue Oct 11 08:14:11 2016	(r307027)
@@ -191,17 +191,9 @@ hv_vmbus_channel_open(
 		return EINVAL;
 	}
 
-	mtx_lock(&new_channel->sc_lock);
-	if (new_channel->state == HV_CHANNEL_OPEN_STATE) {
-	    new_channel->state = HV_CHANNEL_OPENING_STATE;
-	} else {
-	    mtx_unlock(&new_channel->sc_lock);
-	    if(bootverbose)
-		printf("VMBUS: Trying to open channel <%p> which in "
-		    "%d state.\n", new_channel, new_channel->state);
-	    return (EINVAL);
-	}
-	mtx_unlock(&new_channel->sc_lock);
+	if (atomic_testandset_int(&new_channel->ch_stflags,
+	    VMBUS_CHAN_ST_OPENED_SHIFT))
+		panic("double-open chan%u", new_channel->ch_id);
 
 	new_channel->on_channel_callback = pfn_on_channel_callback;
 	new_channel->channel_callback_context = context;
@@ -223,8 +215,10 @@ hv_vmbus_channel_open(
 	    M_DEVBUF, M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0);
 	KASSERT(out != NULL,
 	    ("Error VMBUS: contigmalloc failed to allocate Ring Buffer!"));
-	if (out == NULL)
-		return (ENOMEM);
+	if (out == NULL) {
+		ret = ENOMEM;
+		goto failed;
+	}
 
 	in = ((uint8_t *) out + send_ring_buffer_size);
 
@@ -265,7 +259,8 @@ hv_vmbus_channel_open(
 		device_printf(sc->vmbus_dev,
 		    "can not get msg hypercall for chopen(chan%u)\n",
 		    new_channel->ch_id);
-		return ENXIO;
+		ret = ENXIO;
+		goto failed;
 	}
 
 	req = vmbus_msghc_dataptr(mh);
@@ -284,7 +279,7 @@ hv_vmbus_channel_open(
 		    "chopen(chan%u) msg hypercall exec failed: %d\n",
 		    new_channel->ch_id, ret);
 		vmbus_msghc_put(sc, mh);
-		return ret;
+		goto failed;
 	}
 
 	msg = vmbus_msghc_wait_result(sc, mh);
@@ -294,17 +289,20 @@ hv_vmbus_channel_open(
 	vmbus_msghc_put(sc, mh);
 
 	if (status == 0) {
-		new_channel->state = HV_CHANNEL_OPENED_STATE;
 		if (bootverbose) {
 			device_printf(sc->vmbus_dev, "chan%u opened\n",
 			    new_channel->ch_id);
 		}
-	} else {
-		device_printf(sc->vmbus_dev, "failed to open chan%u\n",
-		    new_channel->ch_id);
-		ret = ENXIO;
+		return 0;
 	}
-	return (ret);
+
+	device_printf(sc->vmbus_dev, "failed to open chan%u\n",
+	    new_channel->ch_id);
+	ret = ENXIO;
+
+failed:
+	atomic_clear_int(&new_channel->ch_stflags, VMBUS_CHAN_ST_OPENED);
+	return ret;
 }
 
 /**
@@ -487,7 +485,9 @@ hv_vmbus_channel_close_internal(hv_vmbus
 	struct taskqueue *rxq = channel->rxq;
 	int error;
 
-	channel->state = HV_CHANNEL_OPEN_STATE;
+	/* TODO: stringent check */
+	atomic_clear_int(&channel->ch_stflags, VMBUS_CHAN_ST_OPENED);
+
 	sysctl_ctx_free(&channel->ch_sysctl_ctx);
 
 	/*
@@ -563,7 +563,7 @@ hv_vmbus_channel_close(hv_vmbus_channel 
 	 */
 	TAILQ_FOREACH(sub_channel, &channel->sc_list_anchor,
 	    sc_list_entry) {
-		if (sub_channel->state != HV_CHANNEL_OPENED_STATE)
+		if ((sub_channel->ch_stflags & VMBUS_CHAN_ST_OPENED) == 0)
 			continue;
 		hv_vmbus_channel_close_internal(sub_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 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/vmbus/hv_channel_mgmt.c	Tue Oct 11 08:14:11 2016	(r307027)
@@ -43,15 +43,12 @@ __FBSDID("$FreeBSD$");
 typedef void	(*vmbus_chanmsg_proc_t)
 		(struct vmbus_softc *, const struct vmbus_message *);
 
-static struct hv_vmbus_channel *hv_vmbus_allocate_channel(struct vmbus_softc *);
-static void	vmbus_channel_on_offer_internal(struct vmbus_softc *,
-		    const struct vmbus_chanmsg_choffer *);
 static void	vmbus_chan_detach_task(void *, int);
 
-static void	vmbus_channel_on_offer(struct vmbus_softc *,
-		    const struct vmbus_message *);
 static void	vmbus_channel_on_offers_delivered(struct vmbus_softc *,
 		    const struct vmbus_message *);
+static void	vmbus_chan_msgproc_choffer(struct vmbus_softc *,
+		    const struct vmbus_message *);
 static void	vmbus_chan_msgproc_chrescind(struct vmbus_softc *,
 		    const struct vmbus_message *);
 
@@ -66,7 +63,7 @@ static void	vmbus_chan_msgproc_chrescind
 
 static const vmbus_chanmsg_proc_t
 vmbus_chanmsg_process[VMBUS_CHANMSG_TYPE_MAX] = {
-	VMBUS_CHANMSG_PROC(CHOFFER,	vmbus_channel_on_offer),
+	VMBUS_CHANMSG_PROC(CHOFFER,	vmbus_chan_msgproc_choffer),
 	VMBUS_CHANMSG_PROC(CHRESCIND,	vmbus_chan_msgproc_chrescind),
 	VMBUS_CHANMSG_PROC(CHOFFER_DONE,vmbus_channel_on_offers_delivered),
 
@@ -79,146 +76,125 @@ vmbus_chanmsg_process[VMBUS_CHANMSG_TYPE
 #undef VMBUS_CHANMSG_PROC_WAKEUP
 #undef VMBUS_CHANMSG_PROC
 
-/**
- * @brief Allocate and initialize a vmbus channel object
- */
 static struct hv_vmbus_channel *
-hv_vmbus_allocate_channel(struct vmbus_softc *sc)
+vmbus_chan_alloc(struct vmbus_softc *sc)
 {
-	struct hv_vmbus_channel *channel;
+	struct hv_vmbus_channel *chan;
 
-	channel = malloc(sizeof(*channel), M_DEVBUF, M_WAITOK | M_ZERO);
-	channel->vmbus_sc = sc;
+	chan = malloc(sizeof(*chan), M_DEVBUF, M_WAITOK | M_ZERO);
 
-	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);
+	chan->ch_monprm = hyperv_dmamem_alloc(bus_get_dma_tag(sc->vmbus_dev),
+	    HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param),
+	    &chan->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
+	if (chan->ch_monprm == NULL) {
+		device_printf(sc->vmbus_dev, "monprm alloc failed\n");
+		free(chan, M_DEVBUF);
+		return NULL;
+	}
 
-	return (channel);
+	chan->vmbus_sc = sc;
+	mtx_init(&chan->sc_lock, "vmbus multi channel", NULL, MTX_DEF);
+	TAILQ_INIT(&chan->sc_list_anchor);
+	TASK_INIT(&chan->ch_detach_task, 0, vmbus_chan_detach_task, chan);
+
+	return chan;
 }
 
-/**
- * @brief Release the resources used by the vmbus channel object
- */
-void
-hv_vmbus_free_vmbus_channel(hv_vmbus_channel* channel)
+static void
+vmbus_chan_free(struct hv_vmbus_channel *chan)
 {
-	mtx_destroy(&channel->sc_lock);
-	free(channel, M_DEVBUF);
+	/* TODO: assert sub-channel list is empty */
+	/* TODO: asset no longer on the primary channel's sub-channel list */
+	/* TODO: asset no longer on the vmbus channel list */
+	hyperv_dmamem_free(&chan->ch_monprm_dma, chan->ch_monprm);
+	mtx_destroy(&chan->sc_lock);
+	free(chan, M_DEVBUF);
 }
 
-/**
- * @brief Process the offer by creating a channel/device
- * associated with this offer
- */
-static void
-vmbus_channel_process_offer(hv_vmbus_channel *new_channel)
+static int
+vmbus_chan_add(struct hv_vmbus_channel *newchan)
 {
-	struct vmbus_softc *sc = new_channel->vmbus_sc;
-	hv_vmbus_channel*	channel;
+	struct vmbus_softc *sc = newchan->vmbus_sc;
+	struct hv_vmbus_channel *prichan;
 
-	/*
-	 * Make sure this is a new offer
-	 */
-	mtx_lock(&sc->vmbus_chlist_lock);
-	if (new_channel->ch_id == 0) {
+	if (newchan->ch_id == 0) {
 		/*
-		 * XXX channel0 will not be processed; skip it.
+		 * XXX
+		 * Chan0 will neither be processed nor should be offered;
+		 * skip it.
 		 */
-		printf("VMBUS: got channel0 offer\n");
-	} else {
-		sc->vmbus_chmap[new_channel->ch_id] = new_channel;
+		device_printf(sc->vmbus_dev, "got chan0 offer, discard\n");
+		return EINVAL;
+	} else if (newchan->ch_id >= VMBUS_CHAN_MAX) {
+		device_printf(sc->vmbus_dev, "invalid chan%u offer\n",
+		    newchan->ch_id);
+		return EINVAL;
 	}
+	sc->vmbus_chmap[newchan->ch_id] = newchan;
 
-	TAILQ_FOREACH(channel, &sc->vmbus_chlist, ch_link) {
-		if (memcmp(&channel->ch_guid_type, &new_channel->ch_guid_type,
+	if (bootverbose) {
+		device_printf(sc->vmbus_dev, "chan%u subidx%u offer\n",
+		    newchan->ch_id, newchan->ch_subidx);
+	}
+
+	mtx_lock(&sc->vmbus_chlist_lock);
+	TAILQ_FOREACH(prichan, &sc->vmbus_chlist, ch_link) {
+		if (memcmp(&prichan->ch_guid_type, &newchan->ch_guid_type,
 		    sizeof(struct hyperv_guid)) == 0 &&
-		    memcmp(&channel->ch_guid_inst, &new_channel->ch_guid_inst,
+		    memcmp(&prichan->ch_guid_inst, &newchan->ch_guid_inst,
 		    sizeof(struct hyperv_guid)) == 0)
 			break;
 	}
-
-	if (channel == NULL) {
-		/* Install the new primary channel */
-		TAILQ_INSERT_TAIL(&sc->vmbus_chlist, new_channel, ch_link);
-	}
-	mtx_unlock(&sc->vmbus_chlist_lock);
-
-	if (bootverbose) {
-		char logstr[64];
-
-		logstr[0] = '\0';
-		if (channel != NULL) {
-			snprintf(logstr, sizeof(logstr), ", primary chan%u",
-			    channel->ch_id);
+	if (VMBUS_CHAN_ISPRIMARY(newchan)) {
+		if (prichan == NULL) {
+			/* Install the new primary channel */
+			TAILQ_INSERT_TAIL(&sc->vmbus_chlist, newchan, ch_link);
+			mtx_unlock(&sc->vmbus_chlist_lock);
+			return 0;
+		} else {
+			mtx_unlock(&sc->vmbus_chlist_lock);
+			device_printf(sc->vmbus_dev, "duplicated primary "
+			    "chan%u\n", newchan->ch_id);
+			return EINVAL;
 		}
-		device_printf(sc->vmbus_dev, "chan%u subchanid%u offer%s\n",
-		    new_channel->ch_id,
-		    new_channel->ch_subidx, logstr);
-	}
-
-	if (channel != NULL) {
-		/*
-		 * Check if this is a sub channel.
-		 */
-		if (new_channel->ch_subidx != 0) {
-			/*
-			 * It is a sub channel offer, process it.
-			 */
-			new_channel->primary_channel = channel;
-			new_channel->ch_dev = channel->ch_dev;
-			mtx_lock(&channel->sc_lock);
-			TAILQ_INSERT_TAIL(&channel->sc_list_anchor,
-			    new_channel, sc_list_entry);
-			mtx_unlock(&channel->sc_lock);
-
-			/*
-			 * Insert the new channel to the end of the global
-			 * channel list.
-			 *
-			 * NOTE:
-			 * The new sub-channel MUST be inserted AFTER it's
-			 * primary channel, so that the primary channel will
-			 * be found in the above loop for its baby siblings.
-			 */
-			mtx_lock(&sc->vmbus_chlist_lock);
-			TAILQ_INSERT_TAIL(&sc->vmbus_chlist, new_channel,
-			    ch_link);
+	} else { /* Sub-channel */
+		if (prichan == NULL) {
 			mtx_unlock(&sc->vmbus_chlist_lock);
-
-			new_channel->state = HV_CHANNEL_OPEN_STATE;
-
-			/*
-			 * Bump up sub-channel count and notify anyone that is
-			 * interested in this sub-channel, after this sub-channel
-			 * is setup.
-			 */
-			mtx_lock(&channel->sc_lock);
-			channel->subchan_cnt++;
-			mtx_unlock(&channel->sc_lock);
-			wakeup(channel);
-
-			return;
+			device_printf(sc->vmbus_dev, "no primary chan for "
+			    "chan%u\n", newchan->ch_id);
+			return EINVAL;
 		}
-
-		printf("VMBUS: duplicated primary channel%u\n",
-		    new_channel->ch_id);
-		hv_vmbus_free_vmbus_channel(new_channel);
-		return;
+		/*
+		 * Found the primary channel for this sub-channel and
+		 * move on.
+		 *
+		 * XXX refcnt prichan
+		 */
 	}
+	mtx_unlock(&sc->vmbus_chlist_lock);
+
+	/*
+	 * This is a sub-channel; link it with the primary channel.
+	 */
+	KASSERT(!VMBUS_CHAN_ISPRIMARY(newchan),
+	    ("new channel is not sub-channel"));
+	KASSERT(prichan != NULL, ("no primary channel"));
 
-	new_channel->state = HV_CHANNEL_OPEN_STATE;
+	newchan->primary_channel = prichan;
+	newchan->ch_dev = prichan->ch_dev;
 
+	mtx_lock(&prichan->sc_lock);
+	TAILQ_INSERT_TAIL(&prichan->sc_list_anchor, newchan, sc_list_entry);
 	/*
-	 * Add the new device to the bus. This will kick off device-driver
-	 * binding which eventually invokes the device driver's AddDevice()
-	 * method.
-	 *
-	 * NOTE:
-	 * Error is ignored here; don't have much to do if error really
-	 * happens.
+	 * Bump up sub-channel count and notify anyone that is
+	 * interested in this sub-channel, after this sub-channel
+	 * is setup.
 	 */
-	hv_vmbus_child_device_register(new_channel);
+	prichan->subchan_cnt++;
+	mtx_unlock(&prichan->sc_lock);
+	wakeup(prichan);
+
+	return 0;
 }
 
 void
@@ -253,7 +229,7 @@ vmbus_channel_cpu_rr(struct hv_vmbus_cha
 }
 
 static void
-vmbus_channel_select_defcpu(struct hv_vmbus_channel *chan)
+vmbus_chan_cpu_default(struct hv_vmbus_channel *chan)
 {
 	/*
 	 * By default, pin the channel to cpu0.  Devices having
@@ -263,69 +239,68 @@ vmbus_channel_select_defcpu(struct hv_vm
 	vmbus_channel_cpu_set(chan, 0);
 }
 
-/**
- * @brief Handler for channel offers from Hyper-V/Azure
- *
- * Handler for channel offers from vmbus in parent partition.
- */
 static void
-vmbus_channel_on_offer(struct vmbus_softc *sc, const struct vmbus_message *msg)
+vmbus_chan_msgproc_choffer(struct vmbus_softc *sc,
+    const struct vmbus_message *msg)
 {
-	/* New channel is offered by vmbus */
-	vmbus_scan_newchan(sc);
+	const struct vmbus_chanmsg_choffer *offer;
+	struct hv_vmbus_channel *chan;
+	int error;
 
-	vmbus_channel_on_offer_internal(sc,
-	    (const struct vmbus_chanmsg_choffer *)msg->msg_data);
-}
+	offer = (const struct vmbus_chanmsg_choffer *)msg->msg_data;
 
-static void
-vmbus_channel_on_offer_internal(struct vmbus_softc *sc,
-    const struct vmbus_chanmsg_choffer *offer)
-{
-	hv_vmbus_channel* new_channel;
+	chan = vmbus_chan_alloc(sc);
+	if (chan == NULL) {
+		device_printf(sc->vmbus_dev, "allocate chan%u failed\n",
+		    offer->chm_chanid);
+		return;
+	}
 
-	/*
-	 * Allocate the channel object and save this offer
-	 */
-	new_channel = hv_vmbus_allocate_channel(sc);
-	new_channel->ch_id = offer->chm_chanid;
-	new_channel->ch_subidx = offer->chm_subidx;
-	new_channel->ch_guid_type = offer->chm_chtype;
-	new_channel->ch_guid_inst = offer->chm_chinst;
+	chan->ch_id = offer->chm_chanid;
+	chan->ch_subidx = offer->chm_subidx;
+	chan->ch_guid_type = offer->chm_chtype;
+	chan->ch_guid_inst = offer->chm_chinst;
 
 	/* Batch reading is on by default */
-	new_channel->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
-	if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF)
-		new_channel->ch_flags |= VMBUS_CHAN_FLAG_HASMNF;
+	chan->ch_flags |= VMBUS_CHAN_FLAG_BATCHREAD;
 
-	new_channel->ch_monprm = hyperv_dmamem_alloc(
-	    bus_get_dma_tag(sc->vmbus_dev),
-	    HYPERCALL_PARAM_ALIGN, 0, sizeof(struct hyperv_mon_param),
-	    &new_channel->ch_monprm_dma, BUS_DMA_WAITOK | BUS_DMA_ZERO);
-	if (new_channel->ch_monprm == NULL) {
-		device_printf(sc->vmbus_dev, "monprm alloc failed\n");
-		/* XXX */
-		mtx_destroy(&new_channel->sc_lock);
-		free(new_channel, M_DEVBUF);
-		return;
-	}
-	new_channel->ch_monprm->mp_connid = VMBUS_CONNID_EVENT;
+	chan->ch_monprm->mp_connid = VMBUS_CONNID_EVENT;
 	if (sc->vmbus_version != VMBUS_VERSION_WS2008)
-		new_channel->ch_monprm->mp_connid = offer->chm_connid;
+		chan->ch_monprm->mp_connid = offer->chm_connid;
 
-	if (new_channel->ch_flags & VMBUS_CHAN_FLAG_HASMNF) {
-		new_channel->ch_montrig_idx =
-		    offer->chm_montrig / VMBUS_MONTRIG_LEN;
-		if (new_channel->ch_montrig_idx >= VMBUS_MONTRIGS_MAX)
+	if (offer->chm_flags1 & VMBUS_CHOFFER_FLAG1_HASMNF) {
+		/*
+		 * Setup MNF stuffs.
+		 */
+		chan->ch_flags |= VMBUS_CHAN_FLAG_HASMNF;
+		chan->ch_montrig_idx = offer->chm_montrig / VMBUS_MONTRIG_LEN;
+		if (chan->ch_montrig_idx >= VMBUS_MONTRIGS_MAX)
 			panic("invalid monitor trigger %u", offer->chm_montrig);
-		new_channel->ch_montrig_mask =
+		chan->ch_montrig_mask =
 		    1 << (offer->chm_montrig % VMBUS_MONTRIG_LEN);
 	}
 
 	/* Select default cpu for this channel. */
-	vmbus_channel_select_defcpu(new_channel);
+	vmbus_chan_cpu_default(chan);
 
-	vmbus_channel_process_offer(new_channel);
+	error = vmbus_chan_add(chan);
+	if (error) {
+		device_printf(sc->vmbus_dev, "add chan%u failed: %d\n",
+		    chan->ch_id, error);
+		vmbus_chan_free(chan);
+		return;
+	}
+
+	if (VMBUS_CHAN_ISPRIMARY(chan)) {
+		/*
+		 * Add device for this primary channel.
+		 *
+		 * NOTE:
+		 * Error is ignored here; don't have much to do if error
+		 * really happens.
+		 */
+		hv_vmbus_child_device_register(chan);
+	}
 }
 
 /*
@@ -363,7 +338,7 @@ vmbus_chan_detach_task(void *xchan, int 
 {
 	struct hv_vmbus_channel *chan = xchan;
 
-	if (HV_VMBUS_CHAN_ISPRIMARY(chan)) {
+	if (VMBUS_CHAN_ISPRIMARY(chan)) {
 		/* Only primary channel owns the device */
 		hv_vmbus_child_device_unregister(chan);
 		/* NOTE: DO NOT free primary channel for now */
@@ -401,10 +376,6 @@ vmbus_chan_detach_task(void *xchan, int 
 			}
 		}
 remove:
-		mtx_lock(&sc->vmbus_chlist_lock);
-		TAILQ_REMOVE(&sc->vmbus_chlist, chan, ch_link);
-		mtx_unlock(&sc->vmbus_chlist_lock);
-
 		mtx_lock(&pri_chan->sc_lock);
 		TAILQ_REMOVE(&pri_chan->sc_list_anchor, chan, sc_list_entry);
 		KASSERT(pri_chan->subchan_cnt > 0,
@@ -413,7 +384,7 @@ remove:
 		mtx_unlock(&pri_chan->sc_lock);
 		wakeup(pri_chan);
 
-		hv_vmbus_free_vmbus_channel(chan);
+		vmbus_chan_free(chan);
 	}
 }
 
@@ -442,13 +413,11 @@ hv_vmbus_release_unattached_channels(str
 
 	while (!TAILQ_EMPTY(&sc->vmbus_chlist)) {
 	    channel = TAILQ_FIRST(&sc->vmbus_chlist);
+	    KASSERT(VMBUS_CHAN_ISPRIMARY(channel), ("not primary channel"));
 	    TAILQ_REMOVE(&sc->vmbus_chlist, channel, ch_link);
 
-	    if (HV_VMBUS_CHAN_ISPRIMARY(channel)) {
-		/* Only primary channel owns the device */
-		hv_vmbus_child_device_unregister(channel);
-	    }
-	    hv_vmbus_free_vmbus_channel(channel);
+	    hv_vmbus_child_device_unregister(channel);
+	    vmbus_chan_free(channel);
 	}
 	bzero(sc->vmbus_chmap,
 	    sizeof(struct hv_vmbus_channel *) * VMBUS_CHAN_MAX);
@@ -486,7 +455,7 @@ vmbus_select_outgoing_channel(struct hv_
 	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){
+		if ((new_channel->ch_stflags & VMBUS_CHAN_ST_OPENED) == 0) {
 			continue;
 		}
 

Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Tue Oct 11 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Tue Oct 11 08:14:11 2016	(r307027)
@@ -55,7 +55,6 @@ typedef struct {
 
 typedef struct {
 	uint32_t 		rel_id;
-	hv_vmbus_channel_state	state;
 	struct hyperv_guid	interface_type;
 	struct hyperv_guid	interface_instance;
 	uint32_t		monitor_id;
@@ -147,7 +146,6 @@ void			hv_ring_buffer_read_begin(
 uint32_t		hv_ring_buffer_read_end(
 				hv_vmbus_ring_buffer_info	*ring_info);
 
-void			hv_vmbus_free_vmbus_channel(hv_vmbus_channel *channel);
 void			hv_vmbus_release_unattached_channels(
 			    struct vmbus_softc *);
 

Modified: stable/10/sys/dev/hyperv/vmbus/vmbus.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus.c	Tue Oct 11 08:01:43 2016	(r307026)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus.c	Tue Oct 11 08:14:11 2016	(r307027)
@@ -1074,6 +1074,9 @@ hv_vmbus_child_device_register(struct hv
 	device_t parent = sc->vmbus_dev;
 	int error = 0;
 
+	/* New channel has been offered */
+	vmbus_scan_newchan(sc);
+
 	chan->ch_dev = device_add_child(parent, NULL, -1);
 	if (chan->ch_dev == NULL) {
 		device_printf(parent, "device_add_child for chan%u failed\n",



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201610110814.u9B8EBnw026673>