Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 13 Oct 2016 08:47:51 +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: r307206 - stable/10/sys/dev/hyperv/netvsc
Message-ID:  <201610130847.u9D8lprY046530@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Thu Oct 13 08:47:51 2016
New Revision: 307206
URL: https://svnweb.freebsd.org/changeset/base/307206

Log:
  MFC 305724,305725,305727-305730,305760,305761,305763,305788
  
  305724
      hyperv/hn: Rename RXBUF connect/disconnect functions.
  
      Minor cleanup and wording in error messages.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7823
  
  305725
      hyperv/hn: Rename chimney sending buffer connect/disconnect functions.
  
      Minor cleanup and wording in error messages.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7825
  
  305727
      hyperv/hn: Function rename.
  
      - Minor style changes.
      - Nuke unnecessary indirection.
      - Nuke unapplied comment.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7827
  
  305728
      hyperv/hn: Reorganize sub-channel allocation.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7829
  
  305729
      hyperv/hn: Reorganize RNDIS attach
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7830
  
  305730
      hyperv/hn: Pull ether address and link status extraction up.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7831
  
  305760
      hyperv/hn: Reorganize channel attach/detach code.
  
      This paves the way for further attach/detach code reorganization.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7858
  
  305761
      hyperv/hn: Regroup synthetic parts attach code.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7859
  
  305763
      hyperv/hn: Reorganize synthetic parts attach code.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7860
  
  305788
      hyperv/hn: Pull RSS key and indirect table setup up.
  
      This paves the way for the dynamic RSS key and indirect table setting.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7864

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

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c	Thu Oct 13 08:35:08 2016	(r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c	Thu Oct 13 08:47:51 2016	(r307206)
@@ -56,11 +56,10 @@ MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper
 /*
  * Forward declarations
  */
-static int  hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc);
-static int  hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *);
-static int  hv_nv_destroy_send_buffer(struct hn_softc *sc);
-static int  hv_nv_destroy_rx_buffer(struct hn_softc *sc);
-static int  hv_nv_connect_to_vsp(struct hn_softc *sc, int mtu);
+static int  hn_nvs_conn_chim(struct hn_softc *sc);
+static int  hn_nvs_conn_rxbuf(struct hn_softc *);
+static int  hn_nvs_disconn_chim(struct hn_softc *sc);
+static int  hn_nvs_disconn_rxbuf(struct hn_softc *sc);
 static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
     struct hn_softc *, struct vmbus_channel *chan,
     const void *, int);
@@ -102,7 +101,7 @@ hn_chim_alloc(struct hn_softc *sc)
 	return (ret);
 }
 
-const void *
+static const void *
 hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact,
     void *req, int reqlen, size_t *resplen0, uint32_t type)
 {
@@ -153,14 +152,8 @@ hn_nvs_req_send(struct hn_softc *sc, voi
 	    req, reqlen, &hn_send_ctx_none));
 }
 
-/*
- * Net VSC initialize receive buffer with net VSP
- * 
- * Net VSP:  Network virtual services client, also known as the
- *     Hyper-V extensible switch and the synthetic data path.
- */
 static int 
-hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
+hn_nvs_conn_rxbuf(struct hn_softc *sc)
 {
 	struct vmbus_xact *xact = NULL;
 	struct hn_nvs_rxbuf_conn *conn;
@@ -187,7 +180,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 	error = vmbus_chan_gpadl_connect(sc->hn_prichan,
 	    sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
 	if (error) {
-		if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n",
+		if_printf(sc->hn_ifp, "rxbuf gpadl conn failed: %d\n",
 		    error);
 		goto cleanup;
 	}
@@ -211,7 +204,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 	resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len,
 	    HN_NVS_TYPE_RXBUF_CONNRESP);
 	if (resp == NULL) {
-		if_printf(sc->hn_ifp, "exec rxbuf conn failed\n");
+		if_printf(sc->hn_ifp, "exec nvs rxbuf conn failed\n");
 		error = EIO;
 		goto cleanup;
 	}
@@ -221,7 +214,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 	xact = NULL;
 
 	if (status != HN_NVS_STATUS_OK) {
-		if_printf(sc->hn_ifp, "rxbuf conn failed: %x\n", status);
+		if_printf(sc->hn_ifp, "nvs rxbuf conn failed: %x\n", status);
 		error = EIO;
 		goto cleanup;
 	}
@@ -232,15 +225,12 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 cleanup:
 	if (xact != NULL)
 		vmbus_xact_put(xact);
-	hv_nv_destroy_rx_buffer(sc);
+	hn_nvs_disconn_rxbuf(sc);
 	return (error);
 }
 
-/*
- * Net VSC initialize send buffer with net VSP
- */
 static int 
-hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
+hn_nvs_conn_chim(struct hn_softc *sc)
 {
 	struct vmbus_xact *xact = NULL;
 	struct hn_nvs_chim_conn *chim;
@@ -260,8 +250,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
   	    sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE,
 	    &sc->hn_chim_gpadl);
 	if (error) {
-		if_printf(sc->hn_ifp, "chimney sending buffer gpadl "
-		    "connect failed: %d\n", error);
+		if_printf(sc->hn_ifp, "chim gpadl conn failed: %d\n", error);
 		goto cleanup;
 	}
 
@@ -284,7 +273,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
 	resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len,
 	    HN_NVS_TYPE_CHIM_CONNRESP);
 	if (resp == NULL) {
-		if_printf(sc->hn_ifp, "exec chim conn failed\n");
+		if_printf(sc->hn_ifp, "exec nvs chim conn failed\n");
 		error = EIO;
 		goto cleanup;
 	}
@@ -295,14 +284,14 @@ hv_nv_init_send_buffer_with_net_vsp(stru
 	xact = NULL;
 
 	if (status != HN_NVS_STATUS_OK) {
-		if_printf(sc->hn_ifp, "chim conn failed: %x\n", status);
+		if_printf(sc->hn_ifp, "nvs chim conn failed: %x\n", status);
 		error = EIO;
 		goto cleanup;
 	}
 	if (sectsz == 0) {
 		if_printf(sc->hn_ifp, "zero chimney sending buffer "
 		    "section size\n");
-		return 0;
+		return (0);
 	}
 
 	sc->hn_chim_szmax = sectsz;
@@ -326,22 +315,19 @@ hv_nv_init_send_buffer_with_net_vsp(stru
 		if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
 		    sc->hn_chim_szmax, sc->hn_chim_cnt);
 	}
-	return 0;
+	return (0);
 
 cleanup:
 	if (xact != NULL)
 		vmbus_xact_put(xact);
-	hv_nv_destroy_send_buffer(sc);
+	hn_nvs_disconn_chim(sc);
 	return (error);
 }
 
-/*
- * Net VSC destroy receive buffer
- */
 static int
-hv_nv_destroy_rx_buffer(struct hn_softc *sc)
+hn_nvs_disconn_rxbuf(struct hn_softc *sc)
 {
-	int ret = 0;
+	int error;
 
 	if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
 		struct hn_nvs_rxbuf_disconn disconn;
@@ -354,38 +340,35 @@ hv_nv_destroy_rx_buffer(struct hn_softc 
 		disconn.nvs_sig = HN_NVS_RXBUF_SIG;
 
 		/* NOTE: No response. */
-		ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
-		if (ret != 0) {
+		error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
+		if (error) {
 			if_printf(sc->hn_ifp,
-			    "send rxbuf disconn failed: %d\n", ret);
-			return (ret);
+			    "send nvs rxbuf disconn failed: %d\n", error);
+			return (error);
 		}
 		sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
 	}
-		
+
 	if (sc->hn_rxbuf_gpadl != 0) {
 		/*
 		 * Disconnect RXBUF from primary channel.
 		 */
-		ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
+		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
 		    sc->hn_rxbuf_gpadl);
-		if (ret != 0) {
+		if (error) {
 			if_printf(sc->hn_ifp,
-			    "rxbuf disconn failed: %d\n", ret);
-			return (ret);
+			    "rxbuf gpadl disconn failed: %d\n", error);
+			return (error);
 		}
 		sc->hn_rxbuf_gpadl = 0;
 	}
-	return (ret);
+	return (0);
 }
 
-/*
- * Net VSC destroy send buffer
- */
 static int
-hv_nv_destroy_send_buffer(struct hn_softc *sc)
+hn_nvs_disconn_chim(struct hn_softc *sc)
 {
-	int ret = 0;
+	int error;
 
 	if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
 		struct hn_nvs_chim_disconn disconn;
@@ -398,25 +381,25 @@ hv_nv_destroy_send_buffer(struct hn_soft
 		disconn.nvs_sig = HN_NVS_CHIM_SIG;
 
 		/* NOTE: No response. */
-		ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
-		if (ret != 0) {
+		error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
+		if (error) {
 			if_printf(sc->hn_ifp,
-			    "send chim disconn failed: %d\n", ret);
-			return (ret);
+			    "send nvs chim disconn failed: %d\n", error);
+			return (error);
 		}
 		sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
 	}
-		
+
 	if (sc->hn_chim_gpadl != 0) {
 		/*
 		 * Disconnect chimney sending buffer from primary channel.
 		 */
-		ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
+		error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
 		    sc->hn_chim_gpadl);
-		if (ret != 0) {
+		if (error) {
 			if_printf(sc->hn_ifp,
-			    "chim disconn failed: %d\n", ret);
-			return (ret);
+			    "chim gpadl disconn failed: %d\n", error);
+			return (error);
 		}
 		sc->hn_chim_gpadl = 0;
 	}
@@ -425,8 +408,7 @@ hv_nv_destroy_send_buffer(struct hn_soft
 		free(sc->hn_chim_bmap, M_NETVSC);
 		sc->hn_chim_bmap = NULL;
 	}
-
-	return (ret);
+	return (0);
 }
 
 static int
@@ -537,38 +519,48 @@ hn_nvs_init(struct hn_softc *sc)
 	return (ENXIO);
 }
 
-static int
-hv_nv_connect_to_vsp(struct hn_softc *sc, int mtu)
+int
+hn_nvs_attach(struct hn_softc *sc, int mtu)
 {
-	int ret;
+	int error;
 
 	/*
 	 * Initialize NVS.
 	 */
-	ret = hn_nvs_init(sc);
-	if (ret != 0)
-		return (ret);
+	error = hn_nvs_init(sc);
+	if (error)
+		return (error);
 
 	if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
 		/*
 		 * Configure NDIS before initializing it.
 		 */
-		ret = hn_nvs_conf_ndis(sc, mtu);
-		if (ret != 0)
-			return (ret);
+		error = hn_nvs_conf_ndis(sc, mtu);
+		if (error)
+			return (error);
 	}
 
 	/*
 	 * Initialize NDIS.
 	 */
-	ret = hn_nvs_init_ndis(sc);
-	if (ret != 0)
-		return (ret);
-
-	ret = hv_nv_init_rx_buffer_with_net_vsp(sc);
-	if (ret == 0)
-		ret = hv_nv_init_send_buffer_with_net_vsp(sc);
-	return (ret);
+	error = hn_nvs_init_ndis(sc);
+	if (error)
+		return (error);
+
+	/*
+	 * Connect RXBUF.
+	 */
+	error = hn_nvs_conn_rxbuf(sc);
+	if (error)
+		return (error);
+
+	/*
+	 * Connect chimney sending buffer.
+	 */
+	error = hn_nvs_conn_chim(sc);
+	if (error)
+		return (error);
+	return (0);
 }
 
 /*
@@ -577,23 +569,8 @@ hv_nv_connect_to_vsp(struct hn_softc *sc
 static void
 hv_nv_disconnect_from_vsp(struct hn_softc *sc)
 {
-	hv_nv_destroy_rx_buffer(sc);
-	hv_nv_destroy_send_buffer(sc);
-}
-
-/*
- * Net VSC on device add
- * 
- * Callback when the device belonging to this driver is added
- */
-int
-hv_nv_on_device_add(struct hn_softc *sc, int mtu)
-{
-
-	/*
-	 * Connect with the NetVsp
-	 */
-	return (hv_nv_connect_to_vsp(sc, mtu));
+	hn_nvs_disconn_rxbuf(sc);
+	hn_nvs_disconn_chim(sc);
 }
 
 /*
@@ -604,11 +581,6 @@ hv_nv_on_device_remove(struct hn_softc *
 {
 	
 	hv_nv_disconnect_from_vsp(sc);
-
-	/* Now, we can close the channel safely */
-
-	vmbus_chan_close(sc->hn_prichan);
-
 	return (0);
 }
 
@@ -675,3 +647,54 @@ hv_nv_on_send(struct vmbus_channel *chan
 
 	return (ret);
 }
+
+int
+hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0)
+{
+	struct vmbus_xact *xact;
+	struct hn_nvs_subch_req *req;
+	const struct hn_nvs_subch_resp *resp;
+	int error, nsubch_req;
+	uint32_t nsubch;
+	size_t resp_len;
+
+	nsubch_req = *nsubch0;
+	KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req));
+
+	xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
+	if (xact == NULL) {
+		if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n");
+		return (ENXIO);
+	}
+	req = vmbus_xact_req_data(xact);
+	req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
+	req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
+	req->nvs_nsubch = nsubch_req;
+
+	resp_len = sizeof(*resp);
+	resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
+	    HN_NVS_TYPE_SUBCH_RESP);
+	if (resp == NULL) {
+		if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n");
+		error = EIO;
+		goto done;
+	}
+	if (resp->nvs_status != HN_NVS_STATUS_OK) {
+		if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n",
+		    resp->nvs_status);
+		error = EIO;
+		goto done;
+	}
+
+	nsubch = resp->nvs_nsubch;
+	if (nsubch > nsubch_req) {
+		if_printf(sc->hn_ifp, "%u subchans are allocated, "
+		    "requested %d\n", nsubch, nsubch_req);
+		nsubch = nsubch_req;
+	}
+	*nsubch0 = nsubch;
+	error = 0;
+done:
+	vmbus_xact_put(xact);
+	return (error);
+}

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Thu Oct 13 08:35:08 2016	(r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Thu Oct 13 08:47:51 2016	(r307206)
@@ -99,11 +99,6 @@ struct vmbus_channel;
 #define NETVSC_DEVICE_RING_BUFFER_SIZE	(128 * PAGE_SIZE)
 #define NETVSC_PACKET_MAXPAGE		32
 
-typedef struct {
-	uint8_t		mac_addr[ETHER_ADDR_LEN];
-	uint32_t	link_state;
-} netvsc_device_info;
-
 #define HN_XACT_REQ_PGCNT		2
 #define HN_XACT_RESP_PGCNT		2
 #define HN_XACT_REQ_SIZE		(HN_XACT_REQ_PGCNT * PAGE_SIZE)
@@ -262,7 +257,7 @@ extern int hv_promisc_mode;
 struct hn_send_ctx;
 
 void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status);
-int hv_nv_on_device_add(struct hn_softc *sc, int mtu);
+int hn_nvs_attach(struct hn_softc *sc, int mtu);
 int hv_nv_on_device_remove(struct hn_softc *sc);
 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/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Thu Oct 13 08:35:08 2016	(r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Thu Oct 13 08:47:51 2016	(r307206)
@@ -349,8 +349,12 @@ static int hn_create_rx_data(struct hn_s
 static void hn_destroy_rx_data(struct hn_softc *sc);
 static void hn_set_chim_size(struct hn_softc *, int);
 static int hn_chan_attach(struct hn_softc *, struct vmbus_channel *);
+static void hn_chan_detach(struct hn_softc *, struct vmbus_channel *);
 static int hn_attach_subchans(struct hn_softc *);
+static void hn_detach_allchans(struct hn_softc *);
 static void hn_chan_callback(struct vmbus_channel *chan, void *xrxr);
+static void hn_set_ring_inuse(struct hn_softc *, int);
+static int hn_synth_attach(struct hn_softc *, int);
 
 static void hn_nvs_handle_notify(struct hn_softc *sc,
 		const struct vmbus_chanpkt_hdr *pkt);
@@ -368,6 +372,14 @@ static void hn_xmit_txeof(struct hn_tx_r
 static void hn_xmit_taskfunc(void *, int);
 static void hn_xmit_txeof_taskfunc(void *, int);
 
+static const uint8_t	hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
+	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
+	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
+	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
+	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
+};
+
 #if __FreeBSD_version >= 1100099
 static void
 hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
@@ -457,7 +469,8 @@ netvsc_attach(device_t dev)
 {
 	struct sysctl_oid_list *child;
 	struct sysctl_ctx_list *ctx;
-	netvsc_device_info device_info;
+	uint8_t eaddr[ETHER_ADDR_LEN];
+	uint32_t link_status;
 	hn_softc_t *sc;
 	int unit = device_get_unit(dev);
 	struct ifnet *ifp = NULL;
@@ -535,9 +548,17 @@ netvsc_attach(device_t dev)
 		goto failed;
 
 	/*
-	 * Associate the first TX/RX ring w/ the primary channel.
+	 * Create transaction context for NVS and RNDIS transactions.
 	 */
-	error = hn_chan_attach(sc, sc->hn_prichan);
+	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
+	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
+	if (sc->hn_xact == NULL)
+		goto failed;
+
+	/*
+	 * Attach the synthetic parts, i.e. NVS and RNDIS.
+	 */
+	error = hn_synth_attach(sc, ETHERMTU);
 	if (error)
 		goto failed;
 
@@ -575,34 +596,6 @@ netvsc_attach(device_t dev)
 	    IFCAP_LRO;
 	ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist | CSUM_TSO;
 
-	sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
-	    HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
-	if (sc->hn_xact == NULL)
-		goto failed;
-
-	error = hv_rf_on_device_add(sc, &device_info, &ring_cnt, ETHERMTU);
-	if (error)
-		goto failed;
-	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_inuse,
-	    ("invalid channel count %d, should be less than %d",
-	     ring_cnt, sc->hn_rx_ring_inuse));
-
-	/*
-	 * Set the # of TX/RX rings that could be used according to
-	 * the # of channels that host offered.
-	 */
-	if (sc->hn_tx_ring_inuse > ring_cnt)
-		sc->hn_tx_ring_inuse = ring_cnt;
-	sc->hn_rx_ring_inuse = ring_cnt;
-	device_printf(dev, "%d TX ring, %d RX ring\n",
-	    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
-
-	if (sc->hn_rx_ring_inuse > 1) {
-		error = hn_attach_subchans(sc);
-		if (error)
-			goto failed;
-	}
-
 #if __FreeBSD_version >= 1100099
 	if (sc->hn_rx_ring_inuse > 1) {
 		/*
@@ -613,9 +606,11 @@ netvsc_attach(device_t dev)
 	}
 #endif
 
-	if (device_info.link_state == NDIS_MEDIA_STATE_CONNECTED) {
+	error = hn_rndis_get_linkstatus(sc, &link_status);
+	if (error)
+		goto failed;
+	if (link_status == NDIS_MEDIA_STATE_CONNECTED)
 		sc->hn_carrier = 1;
-	}
 
 	tso_maxlen = hn_tso_maxlen;
 	if (tso_maxlen <= 0 || tso_maxlen > IP_MAXPACKET)
@@ -626,7 +621,10 @@ netvsc_attach(device_t dev)
 	ifp->if_hw_tsomax = tso_maxlen -
 	    (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
 
-	ether_ifattach(ifp, device_info.mac_addr);
+	error = hn_rndis_get_eaddr(sc, eaddr);
+	if (error)
+		goto failed;
+	ether_ifattach(ifp, eaddr);
 
 	if_printf(ifp, "TSO: %u/%u/%u\n", ifp->if_hw_tsomax,
 	    ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
@@ -675,6 +673,7 @@ netvsc_detach(device_t dev)
 	 */
 
 	hv_rf_on_device_remove(sc);
+	hn_detach_allchans(sc);
 
 	hn_stop_tx_tasks(sc);
 
@@ -1519,8 +1518,7 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 #ifdef INET
 	struct ifaddr *ifa = (struct ifaddr *)data;
 #endif
-	netvsc_device_info device_info;
-	int mask, error = 0, ring_cnt;
+	int mask, error = 0;
 	int retry_cnt = 500;
 	
 	switch(cmd) {
@@ -1591,43 +1589,16 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 			break;
 		}
 
-		/* Wait for subchannels to be destroyed */
-		vmbus_subchan_drain(sc->hn_prichan);
-
-		sc->hn_rx_ring[0].hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
-		sc->hn_tx_ring[0].hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
-		hn_chan_attach(sc, sc->hn_prichan); /* XXX check error */
-
-		ring_cnt = sc->hn_rx_ring_inuse;
-		error = hv_rf_on_device_add(sc, &device_info, &ring_cnt,
-		    ifr->ifr_mtu);
-		if (error) {
-			NV_LOCK(sc);
-			sc->temp_unusable = FALSE;
-			NV_UNLOCK(sc);
-			break;
-		}
-		/* # of channels can _not_ be changed */
-		KASSERT(sc->hn_rx_ring_inuse == ring_cnt,
-		    ("RX ring count %d and channel count %u mismatch",
-		     sc->hn_rx_ring_cnt, ring_cnt));
-		if (sc->hn_rx_ring_inuse > 1) {
-			int r;
+		/*
+		 * Detach all of the channels.
+		 */
+		hn_detach_allchans(sc);
 
-			/*
-			 * Skip the rings on primary channel; they are
-			 * handled by the hv_rf_on_device_add() above.
-			 */
-			for (r = 1; r < sc->hn_rx_ring_cnt; ++r) {
-				sc->hn_rx_ring[r].hn_rx_flags &=
-				    ~HN_RX_FLAG_ATTACHED;
-			}
-			for (r = 1; r < sc->hn_tx_ring_cnt; ++r) {
-				sc->hn_tx_ring[r].hn_tx_flags &=
-				    ~HN_TX_FLAG_ATTACHED;
-			}
-			hn_attach_subchans(sc); /* XXX check error */
-		}
+		/*
+		 * Attach the synthetic parts, i.e. NVS and RNDIS.
+		 * XXX check error.
+		 */
+		hn_synth_attach(sc, ifr->ifr_mtu);
 
 		if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
 			hn_set_chim_size(sc, sc->hn_chim_szmax);
@@ -3073,6 +3044,42 @@ hn_chan_attach(struct hn_softc *sc, stru
 	return (error);
 }
 
+static void
+hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
+{
+	struct hn_rx_ring *rxr;
+	int idx;
+
+	idx = vmbus_chan_subidx(chan);
+
+	/*
+	 * Link this channel to RX/TX ring.
+	 */
+	KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
+	    ("invalid channel index %d, should > 0 && < %d",
+	     idx, sc->hn_rx_ring_inuse));
+	rxr = &sc->hn_rx_ring[idx];
+	KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
+	    ("RX ring %d is not attached", idx));
+	rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
+
+	if (idx < sc->hn_tx_ring_inuse) {
+		struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
+
+		KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
+		    ("TX ring %d is not attached attached", idx));
+		txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
+	}
+
+	/*
+	 * Close this channel.
+	 *
+	 * NOTE:
+	 * Channel closing does _not_ destroy the target channel.
+	 */
+	vmbus_chan_close(chan);
+}
+
 static int
 hn_attach_subchans(struct hn_softc *sc)
 {
@@ -3080,17 +3087,16 @@ hn_attach_subchans(struct hn_softc *sc)
 	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
 	int i, error = 0;
 
-	/* Wait for sub-channels setup to complete. */
-	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
+	if (subchan_cnt == 0)
+		return (0);
 
 	/* Attach the sub-channels. */
+	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
 	for (i = 0; i < subchan_cnt; ++i) {
 		error = hn_chan_attach(sc, subchans[i]);
 		if (error)
 			break;
 	}
-
-	/* Release the sub-channels */
 	vmbus_subchan_rel(subchans, subchan_cnt);
 
 	if (error) {
@@ -3105,6 +3111,202 @@ hn_attach_subchans(struct hn_softc *sc)
 }
 
 static void
+hn_detach_allchans(struct hn_softc *sc)
+{
+	struct vmbus_channel **subchans;
+	int subchan_cnt = sc->hn_rx_ring_inuse - 1;
+	int i;
+
+	if (subchan_cnt == 0)
+		goto back;
+
+	/* Detach the sub-channels. */
+	subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
+	for (i = 0; i < subchan_cnt; ++i)
+		hn_chan_detach(sc, subchans[i]);
+	vmbus_subchan_rel(subchans, subchan_cnt);
+
+back:
+	/*
+	 * Detach the primary channel, _after_ all sub-channels
+	 * are detached.
+	 */
+	hn_chan_detach(sc, sc->hn_prichan);
+
+	/* Wait for sub-channels to be destroyed, if any. */
+	vmbus_subchan_drain(sc->hn_prichan);
+
+#ifdef INVARIANTS
+	for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
+		KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
+		    HN_RX_FLAG_ATTACHED) == 0,
+		    ("%dth RX ring is still attached", i));
+	}
+	for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
+		KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
+		    HN_TX_FLAG_ATTACHED) == 0,
+		    ("%dth TX ring is still attached", i));
+	}
+#endif
+}
+
+static int
+hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
+{
+	struct vmbus_channel **subchans;
+	int nchan, rxr_cnt, error;
+
+	nchan = *nsubch + 1;
+	if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) {
+		/*
+		 * Either RSS is not supported, or multiple RX/TX rings
+		 * are not requested.
+		 */
+		*nsubch = 0;
+		return (0);
+	}
+
+	/*
+	 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
+	 * table entries.
+	 */
+	error = hn_rndis_get_rsscaps(sc, &rxr_cnt);
+	if (error) {
+		/* No RSS; this is benign. */
+		*nsubch = 0;
+		return (0);
+	}
+	if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
+	    rxr_cnt, nchan);
+
+	if (nchan > rxr_cnt)
+		nchan = rxr_cnt;
+	if (nchan == 1) {
+		if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
+		*nsubch = 0;
+		return (0);
+	}
+	
+	/*
+	 * Allocate sub-channels from NVS.
+	 */
+	*nsubch = nchan - 1;
+	error = hn_nvs_alloc_subchans(sc, nsubch);
+	if (error || *nsubch == 0) {
+		/* Failed to allocate sub-channels. */
+		*nsubch = 0;
+		return (0);
+	}
+
+	/*
+	 * Wait for all sub-channels to become ready before moving on.
+	 */
+	subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
+	vmbus_subchan_rel(subchans, *nsubch);
+	return (0);
+}
+
+static int
+hn_synth_attach(struct hn_softc *sc, int mtu)
+{
+	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
+	int error, nsubch, nchan, i;
+
+	/*
+	 * Attach the primary channel _before_ attaching NVS and RNDIS.
+	 */
+	error = hn_chan_attach(sc, sc->hn_prichan);
+	if (error)
+		return (error);
+
+	/*
+	 * Attach NVS.
+	 */
+	error = hn_nvs_attach(sc, mtu);
+	if (error)
+		return (error);
+
+	/*
+	 * Attach RNDIS _after_ NVS is attached.
+	 */
+	error = hn_rndis_attach(sc);
+	if (error)
+		return (error);
+
+	/*
+	 * Allocate sub-channels for multi-TX/RX rings.
+	 *
+	 * NOTE:
+	 * The # of RX rings that can be used is equivalent to the # of
+	 * channels to be requested.
+	 */
+	nsubch = sc->hn_rx_ring_cnt - 1;
+	error = hn_synth_alloc_subchans(sc, &nsubch);
+	if (error)
+		return (error);
+
+	nchan = nsubch + 1;
+	if (nchan == 1) {
+		/* Only the primary channel can be used; done */
+		goto back;
+	}
+
+	/*
+	 * Configure RSS key and indirect table _after_ all sub-channels
+	 * are allocated.
+	 */
+
+	/* Setup default RSS key. */
+	memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key));
+
+	/* Setup default RSS indirect table. */
+	/* TODO: Take ndis_rss_caps.ndis_nind into account. */
+	for (i = 0; i < NDIS_HASH_INDCNT; ++i)
+		rss->rss_ind[i] = i % nchan;
+
+	error = hn_rndis_conf_rss(sc);
+	if (error) {
+		/*
+		 * Failed to configure RSS key or indirect table; only
+		 * the primary channel can be used.
+		 */
+		nchan = 1;
+	}
+back:
+	/*
+	 * Set the # of TX/RX rings that could be used according to
+	 * the # of channels that NVS offered.
+	 */
+	hn_set_ring_inuse(sc, nchan);
+
+	/*
+	 * Attach the sub-channels, if any.
+	 */
+	error = hn_attach_subchans(sc);
+	if (error)
+		return (error);
+	return (0);
+}
+
+static void
+hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
+{
+	KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
+	    ("invalid ring count %d", ring_cnt));
+
+	if (sc->hn_tx_ring_cnt > ring_cnt)
+		sc->hn_tx_ring_inuse = ring_cnt;
+	else
+		sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
+	sc->hn_rx_ring_inuse = ring_cnt;
+
+	if (bootverbose) {
+		if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
+		    sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
+	}
+}
+
+static void
 hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
 {
 	const struct hn_nvs_hdr *hdr;

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Thu Oct 13 08:35:08 2016	(r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Thu Oct 13 08:47:51 2016	(r307206)
@@ -76,18 +76,12 @@ static void hv_rf_receive_indicate_statu
     const void *data, int dlen);
 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
     const void *data, int dlen);
-static int hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr);
-static int hv_rf_query_device_link_status(struct hn_softc *sc,
-    uint32_t *link_status);
-static int  hv_rf_init_device(struct hn_softc *sc);
 
 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
     const void *idata, size_t idlen, void *odata, size_t *odlen0);
 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
     size_t dlen);
 static int hn_rndis_conf_offload(struct hn_softc *sc);
-static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
-static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
 
 static __inline uint32_t
 hn_rndis_rid(struct hn_softc *sc)
@@ -481,11 +475,8 @@ hv_rf_on_receive(struct hn_softc *sc, st
 	}
 }
 
-/*
- * RNDIS filter query device MAC address
- */
-static int
-hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr)
+int
+hn_rndis_get_eaddr(struct hn_softc *sc, uint8_t *eaddr)
 {
 	size_t eaddr_len;
 	int error;
@@ -502,11 +493,8 @@ hv_rf_query_device_mac(struct hn_softc *
 	return (0);
 }
 
-/*
- * RNDIS filter query device link status
- */
-static int
-hv_rf_query_device_link_status(struct hn_softc *sc, uint32_t *link_status)
+int
+hn_rndis_get_linkstatus(struct hn_softc *sc, uint32_t *link_status)
 {
 	size_t size;
 	int error;
@@ -523,14 +511,6 @@ hv_rf_query_device_link_status(struct hn
 	return (0);
 }
 
-static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
-	0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
-	0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
-	0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
-	0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
-	0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
-};
-
 static const void *
 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
     struct hn_send_ctx *sndc, size_t *comp_len)
@@ -722,7 +702,7 @@ done:
 	return (error);
 }
 
-static int
+int
 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
 {
 	struct ndis_rss_caps in, caps;
@@ -857,12 +837,12 @@ hn_rndis_conf_offload(struct hn_softc *s
 	return (error);
 }
 
-static int
-hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
+int
+hn_rndis_conf_rss(struct hn_softc *sc)
 {
 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
 	struct ndis_rss_params *prm = &rss->rss_params;
-	int i, error;
+	int error;
 
 	/*
 	 * Only NDIS 6.30+ is supported.
@@ -870,7 +850,12 @@ hn_rndis_conf_rss(struct hn_softc *sc, i
 	KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
 	    ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
 
-	memset(rss, 0, sizeof(*rss));
+	/*
+	 * NOTE:
+	 * DO NOT whack rss_key and rss_ind, which are setup by the caller.
+	 */
+	memset(prm, 0, sizeof(*prm));
+
 	prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
 	prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
 	prm->ndis_hdr.ndis_size = sizeof(*rss);
@@ -885,14 +870,6 @@ hn_rndis_conf_rss(struct hn_softc *sc, i
 	prm->ndis_keyoffset =
 	    __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
 
-	/* Setup RSS key */
-	memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
-
-	/* Setup RSS indirect table */
-	/* TODO: Take ndis_rss_caps.ndis_nind into account */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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