svn commit: r307614 - in stable/11/sys/dev/hyperv: include netvsc vmbus

Sepherosa Ziehau sephe at FreeBSD.org
Wed Oct 19 07:27:47 UTC 2016


Author: sephe
Date: Wed Oct 19 07:27:45 2016
New Revision: 307614
URL: https://svnweb.freebsd.org/changeset/base/307614

Log:
  MFC 307012,307013,307262
  
  307012
      hyperv/vmbus: Allow driver to inject synchronous task into channel taskq.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8208
  
  307013
      hyperv/hn: Rework link status support.
  
      This is the preamble for network device SR-IOV and
      NDIS_STATUS_NETWORK_CHANGE handling.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8209
  
  307262
      hyperv/hn: Management parts always need suspend and resume.
  
      Sponsored by:   Microsoft

Modified:
  stable/11/sys/dev/hyperv/include/vmbus.h
  stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h
  stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  stable/11/sys/dev/hyperv/netvsc/if_hnvar.h
  stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/hyperv/include/vmbus.h
==============================================================================
--- stable/11/sys/dev/hyperv/include/vmbus.h	Wed Oct 19 07:24:32 2016	(r307613)
+++ stable/11/sys/dev/hyperv/include/vmbus.h	Wed Oct 19 07:27:45 2016	(r307614)
@@ -117,6 +117,7 @@ struct vmbus_chan_br {
 
 struct vmbus_channel;
 struct hyperv_guid;
+struct task;
 
 typedef void	(*vmbus_chan_callback_t)(struct vmbus_channel *, void *);
 
@@ -134,6 +135,8 @@ int		vmbus_chan_open_br(struct vmbus_cha
 		    int udlen, vmbus_chan_callback_t cb, void *cbarg);
 void		vmbus_chan_close(struct vmbus_channel *chan);
 void		vmbus_chan_intr_drain(struct vmbus_channel *chan);
+void		vmbus_chan_run_task(struct vmbus_channel *chan,
+		    struct task *task);
 
 int		vmbus_chan_gpadl_connect(struct vmbus_channel *chan,
 		    bus_addr_t paddr, int size, uint32_t *gpadl);

Modified: stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h	Wed Oct 19 07:24:32 2016	(r307613)
+++ stable/11/sys/dev/hyperv/netvsc/hv_net_vsc.h	Wed Oct 19 07:27:45 2016	(r307614)
@@ -233,6 +233,10 @@ struct hn_softc {
 	struct vmbus_xact_ctx *hn_xact;
 	uint32_t	hn_nvs_ver;
 
+	struct taskqueue	*hn_mgmt_taskq;
+	struct taskqueue	*hn_mgmt_taskq0;
+	struct task		hn_link_task;
+
 	uint32_t		hn_caps;	/* HN_CAP_ */
 	uint32_t		hn_flags;	/* HN_FLAG_ */
 	void			*hn_rxbuf;
@@ -271,7 +275,6 @@ struct hn_softc {
  */
 struct hn_send_ctx;
 
-void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status);
 int hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype,
 	struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt);
 

Modified: stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Wed Oct 19 07:24:32 2016	(r307613)
+++ stable/11/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Wed Oct 19 07:27:45 2016	(r307614)
@@ -334,6 +334,8 @@ static void hn_fixup_tx_data(struct hn_s
 static void hn_destroy_tx_data(struct hn_softc *);
 static void hn_start_taskfunc(void *, int);
 static void hn_start_txeof_taskfunc(void *, int);
+static void hn_link_taskfunc(void *, int);
+static void hn_suspend_mgmt_taskfunc(void *, int);
 static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
 static int hn_create_rx_data(struct hn_softc *sc, int);
 static void hn_destroy_rx_data(struct hn_softc *sc);
@@ -349,7 +351,11 @@ static int hn_synth_attach(struct hn_sof
 static void hn_synth_detach(struct hn_softc *);
 static bool hn_tx_ring_pending(struct hn_tx_ring *);
 static void hn_suspend(struct hn_softc *);
+static void hn_suspend_data(struct hn_softc *);
+static void hn_suspend_mgmt(struct hn_softc *);
 static void hn_resume(struct hn_softc *);
+static void hn_resume_data(struct hn_softc *);
+static void hn_resume_mgmt(struct hn_softc *);
 static void hn_rx_drain(struct vmbus_channel *);
 static void hn_tx_resume(struct hn_softc *, int);
 static void hn_tx_ring_qflush(struct hn_tx_ring *);
@@ -518,7 +524,6 @@ netvsc_attach(device_t dev)
 	struct sysctl_oid_list *child;
 	struct sysctl_ctx_list *ctx;
 	uint8_t eaddr[ETHER_ADDR_LEN];
-	uint32_t link_status;
 	struct ifnet *ifp = NULL;
 	int error, ring_cnt, tx_ring_cnt;
 
@@ -551,6 +556,15 @@ netvsc_attach(device_t dev)
 	}
 
 	/*
+	 * Setup taskqueue for mangement tasks, e.g. link status.
+	 */
+	sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
+	    taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
+	taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
+	    device_get_nameunit(dev));
+	TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
+
+	/*
 	 * Allocate ifnet and setup its name earlier, so that if_printf
 	 * can be used by functions, which will be called after
 	 * ether_ifattach().
@@ -621,12 +635,6 @@ netvsc_attach(device_t dev)
 	if (error)
 		goto failed;
 
-	error = hn_rndis_get_linkstatus(sc, &link_status);
-	if (error)
-		goto failed;
-	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
-		sc->hn_carrier = 1;
-
 	error = hn_rndis_get_eaddr(sc, eaddr);
 	if (error)
 		goto failed;
@@ -736,6 +744,12 @@ netvsc_attach(device_t dev)
 	/* Inform the upper layer about the long frame support. */
 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
 
+	/*
+	 * Kick off link status check.
+	 */
+	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
+	hn_link_status_update(sc);
+
 	return (0);
 failed:
 	if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
@@ -755,6 +769,12 @@ netvsc_detach(device_t dev)
 		if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 				hn_stop(sc);
+			/*
+			 * NOTE:
+			 * hn_stop() only suspends data, so managment
+			 * stuffs have to be suspended manually here.
+			 */
+			hn_suspend_mgmt(sc);
 			hn_synth_detach(sc);
 		}
 		HN_UNLOCK(sc);
@@ -767,6 +787,7 @@ netvsc_detach(device_t dev)
 
 	if (sc->hn_tx_taskq != hn_tx_taskq)
 		taskqueue_free(sc->hn_tx_taskq);
+	taskqueue_free(sc->hn_mgmt_taskq0);
 
 	if (sc->hn_xact != NULL)
 		vmbus_xact_ctx_destroy(sc->hn_xact);
@@ -786,6 +807,36 @@ netvsc_shutdown(device_t dev)
 	return (0);
 }
 
+static void
+hn_link_taskfunc(void *xsc, int pending __unused)
+{
+	struct hn_softc *sc = xsc;
+	struct ifnet *ifp = sc->hn_ifp;
+	uint32_t link_status;
+	int error;
+
+	error = hn_rndis_get_linkstatus(sc, &link_status);
+	if (error) {
+		/* XXX what to do? */
+		return;
+	}
+
+	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
+		sc->hn_carrier = 1;
+	else
+		sc->hn_carrier = 0;
+	if_link_state_change(ifp,
+	    sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN);
+}
+
+void
+hn_link_status_update(struct hn_softc *sc)
+{
+
+	if (sc->hn_mgmt_taskq != NULL)
+		taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
+}
+
 static __inline int
 hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
     struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
@@ -1311,19 +1362,6 @@ hn_start_locked(struct hn_tx_ring *txr, 
 }
 
 /*
- * Link up/down notification
- */
-void
-netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status)
-{
-	if (status == 1) {
-		sc->hn_carrier = 1;
-	} else {
-		sc->hn_carrier = 0;
-	}
-}
-
-/*
  * Append the specified data to the indicated mbuf chain,
  * Extend the mbuf chain if the new data does not fit in
  * existing space.
@@ -1653,8 +1691,11 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 			hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
 #endif
 
-		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-			hn_suspend(sc);
+		/*
+		 * Suspend this interface before the synthetic parts
+		 * are ripped.
+		 */
+		hn_suspend(sc);
 
 		/*
 		 * Detach the synthetics parts, i.e. NVS and RNDIS.
@@ -1672,9 +1713,10 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 			hn_set_chim_size(sc, sc->hn_chim_szmax);
 		hn_set_tso_maxsize(sc, hn_tso_maxlen, ifr->ifr_mtu);
 
-		/* All done!  Resume now. */
-		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
-			hn_resume(sc);
+		/*
+		 * All done!  Resume the interface now.
+		 */
+		hn_resume(sc);
 
 		HN_UNLOCK(sc);
 		break;
@@ -1801,9 +1843,9 @@ hn_stop(struct hn_softc *sc)
 	KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
 	    ("synthetic parts were not attached"));
 
-	/* Clear RUNNING bit _before_ hn_suspend() */
+	/* Clear RUNNING bit _before_ hn_suspend_data() */
 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
-	hn_suspend(sc);
+	hn_suspend_data(sc);
 
 	/* Clear OACTIVE bit. */
 	atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
@@ -1896,9 +1938,6 @@ hn_init_locked(struct hn_softc *sc)
 
 	/* Everything is ready; unleash! */
 	atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
-
-	/* TODO: check RNDIS link status. */
-	if_link_state_change(ifp, LINK_STATE_UP);
 }
 
 static void
@@ -3600,7 +3639,7 @@ hn_rx_drain(struct vmbus_channel *chan)
 }
 
 static void
-hn_suspend(struct hn_softc *sc)
+hn_suspend_data(struct hn_softc *sc)
 {
 	struct vmbus_channel **subch = NULL;
 	int i, nsubch;
@@ -3654,6 +3693,42 @@ hn_suspend(struct hn_softc *sc)
 }
 
 static void
+hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
+{
+
+	((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
+}
+
+static void
+hn_suspend_mgmt(struct hn_softc *sc)
+{
+	struct task task;
+
+	HN_LOCK_ASSERT(sc);
+
+	/*
+	 * Make sure that hn_mgmt_taskq0 can nolonger be accessed
+	 * through hn_mgmt_taskq.
+	 */
+	TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
+	vmbus_chan_run_task(sc->hn_prichan, &task);
+
+	/*
+	 * Make sure that all pending management tasks are completed.
+	 */
+	taskqueue_drain_all(sc->hn_mgmt_taskq0);
+}
+
+static void
+hn_suspend(struct hn_softc *sc)
+{
+
+	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
+		hn_suspend_data(sc);
+	hn_suspend_mgmt(sc);
+}
+
+static void
 hn_tx_resume(struct hn_softc *sc, int tx_ring_cnt)
 {
 	int i;
@@ -3671,7 +3746,7 @@ hn_tx_resume(struct hn_softc *sc, int tx
 }
 
 static void
-hn_resume(struct hn_softc *sc)
+hn_resume_data(struct hn_softc *sc)
 {
 	int i;
 
@@ -3685,7 +3760,8 @@ hn_resume(struct hn_softc *sc)
 
 	/*
 	 * Make sure to clear suspend status on "all" TX rings,
-	 * since hn_tx_ring_inuse can be changed after hn_suspend().
+	 * since hn_tx_ring_inuse can be changed after
+	 * hn_suspend_data().
 	 */
 	hn_tx_resume(sc, sc->hn_tx_ring_cnt);
 
@@ -3713,6 +3789,26 @@ hn_resume(struct hn_softc *sc)
 }
 
 static void
+hn_resume_mgmt(struct hn_softc *sc)
+{
+
+	/*
+	 * Kick off link status check.
+	 */
+	sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
+	hn_link_status_update(sc);
+}
+
+static void
+hn_resume(struct hn_softc *sc)
+{
+
+	if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
+		hn_resume_data(sc);
+	hn_resume_mgmt(sc);
+}
+
+static void
 hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
 {
 	const struct hn_nvs_hdr *hdr;

Modified: stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Wed Oct 19 07:24:32 2016	(r307613)
+++ stable/11/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Wed Oct 19 07:27:45 2016	(r307614)
@@ -167,11 +167,8 @@ hv_rf_receive_indicate_status(struct hn_
 
 	switch (msg->rm_status) {
 	case RNDIS_STATUS_MEDIA_CONNECT:
-		netvsc_linkstatus_callback(sc, 1);
-		break;
-
 	case RNDIS_STATUS_MEDIA_DISCONNECT:
-		netvsc_linkstatus_callback(sc, 0);
+		hn_link_status_update(sc);
 		break;
 
 	case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:

Modified: stable/11/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- stable/11/sys/dev/hyperv/netvsc/if_hnvar.h	Wed Oct 19 07:24:32 2016	(r307613)
+++ stable/11/sys/dev/hyperv/netvsc/if_hnvar.h	Wed Oct 19 07:27:45 2016	(r307614)
@@ -138,6 +138,7 @@ void		hn_nvs_sent_xact(struct hn_send_ct
 int		hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
 		    const struct hn_recvinfo *info);
 void		hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
+void		hn_link_status_update(struct hn_softc *sc);
 
 extern struct hn_send_ctx	hn_send_ctx_none;
 

Modified: stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c
==============================================================================
--- stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c	Wed Oct 19 07:24:32 2016	(r307613)
+++ stable/11/sys/dev/hyperv/vmbus/vmbus_chan.c	Wed Oct 19 07:27:45 2016	(r307614)
@@ -1713,3 +1713,11 @@ vmbus_chan_rx_empty(const struct vmbus_c
 
 	return (vmbus_rxbr_empty(&chan->ch_rxbr));
 }
+
+void
+vmbus_chan_run_task(struct vmbus_channel *chan, struct task *task)
+{
+
+	taskqueue_enqueue(chan->ch_tq, task);
+	taskqueue_drain(chan->ch_tq, task);
+}


More information about the svn-src-all mailing list