Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Nov 2016 05:07:25 +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: r308502 - stable/10/sys/dev/hyperv/netvsc
Message-ID:  <201611110507.uAB57PAE030465@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Fri Nov 11 05:07:25 2016
New Revision: 308502
URL: https://svnweb.freebsd.org/changeset/base/308502

Log:
  MFC 307983
  
      hyperv/hn: Properly configure RSS according to RSS capabilities
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8338

Modified:
  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/ndis.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Nov 11 04:39:02 2016	(r308501)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h	Fri Nov 11 05:07:25 2016	(r308502)
@@ -256,6 +256,8 @@ struct hn_softc {
 	int			hn_ndis_tso_szmax;
 	int			hn_ndis_tso_sgmin;
 
+	int			hn_rss_ind_size;
+	uint32_t		hn_rss_hash;	/* NDIS_HASH_ */
 	struct ndis_rssprm_toeplitz hn_rss;
 };
 

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Nov 11 04:39:02 2016	(r308501)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c	Fri Nov 11 05:07:25 2016	(r308502)
@@ -331,6 +331,7 @@ static int hn_hwassist_sysctl(SYSCTL_HAN
 static int hn_rxfilter_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS);
+static int hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS);
 static int hn_check_iplen(const struct mbuf *, int);
 static int hn_create_tx_ring(struct hn_softc *, int);
 static void hn_destroy_tx_ring(struct hn_tx_ring *);
@@ -786,6 +787,11 @@ netvsc_attach(device_t dev)
 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rxfilter",
 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
 	    hn_rxfilter_sysctl, "A", "rxfilter");
+	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_hash",
+	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
+	    hn_rss_hash_sysctl, "A", "RSS hash");
+	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "rss_ind_size",
+	    CTLFLAG_RD, &sc->hn_rss_ind_size, 0, "RSS indirect entry count");
 	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key",
 	    CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
 	    hn_rss_key_sysctl, "IU", "RSS key");
@@ -2499,6 +2505,20 @@ back:
 }
 
 static int
+hn_rss_hash_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	struct hn_softc *sc = arg1;
+	char hash_str[128];
+	uint32_t hash;
+
+	HN_LOCK(sc);
+	hash = sc->hn_rss_hash;
+	HN_UNLOCK(sc);
+	snprintf(hash_str, sizeof(hash_str), "%b", hash, NDIS_HASH_BITS);
+	return sysctl_handle_string(oidp, hash_str, sizeof(hash_str), req);
+}
+
+static int
 hn_check_iplen(const struct mbuf *m, int hoff)
 {
 	const struct ip *ip;
@@ -3662,6 +3682,10 @@ hn_synth_attach(struct hn_softc *sc, int
 	old_caps = sc->hn_caps;
 	sc->hn_caps = 0;
 
+	/* Clear RSS stuffs. */
+	sc->hn_rss_ind_size = 0;
+	sc->hn_rss_hash = 0;
+
 	/*
 	 * Attach the primary channel _before_ attaching NVS and RNDIS.
 	 */
@@ -3736,7 +3760,6 @@ hn_synth_attach(struct hn_softc *sc, int
 			if_printf(sc->hn_ifp, "setup default RSS indirect "
 			    "table\n");
 		}
-		/* TODO: Take ndis_rss_caps.ndis_nind into account. */
 		for (i = 0; i < NDIS_HASH_INDCNT; ++i)
 			rss->rss_ind[i] = i % nchan;
 		sc->hn_flags |= HN_FLAG_HAS_RSSIND;

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Nov 11 04:39:02 2016	(r308501)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c	Fri Nov 11 05:07:25 2016	(r308502)
@@ -748,13 +748,14 @@ done:
 }
 
 int
-hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt)
+hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt0)
 {
 	struct ndis_rss_caps in, caps;
 	size_t caps_len;
-	int error;
+	int error, indsz, rxr_cnt, hash_fnidx;
+	uint32_t hash_func = 0, hash_types = 0;
 
-	*rxr_cnt = 0;
+	*rxr_cnt0 = 0;
 
 	if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_20)
 		return (EOPNOTSUPP);
@@ -793,18 +794,73 @@ hn_rndis_query_rsscaps(struct hn_softc *
 		return (EINVAL);
 	}
 
+	/*
+	 * Save information for later RSS configuration.
+	 */
 	if (caps.ndis_nrxr == 0) {
 		if_printf(sc->hn_ifp, "0 RX rings!?\n");
 		return (EINVAL);
 	}
-	*rxr_cnt = caps.ndis_nrxr;
+	if (bootverbose)
+		if_printf(sc->hn_ifp, "%u RX rings\n", caps.ndis_nrxr);
+	rxr_cnt = caps.ndis_nrxr;
+
+	if (caps.ndis_hdr.ndis_size == NDIS_RSS_CAPS_SIZE &&
+	    caps.ndis_hdr.ndis_rev >= NDIS_RSS_CAPS_REV_2) {
+		if (caps.ndis_nind > NDIS_HASH_INDCNT) {
+			if_printf(sc->hn_ifp,
+			    "too many RSS indirect table entries %u\n",
+			    caps.ndis_nind);
+			return (EOPNOTSUPP);
+		}
+		if (!powerof2(caps.ndis_nind)) {
+			if_printf(sc->hn_ifp, "RSS indirect table size is not "
+			    "power-of-2 %u\n", caps.ndis_nind);
+		}
 
-	if (caps.ndis_hdr.ndis_size == NDIS_RSS_CAPS_SIZE) {
 		if (bootverbose) {
 			if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
 			    caps.ndis_nind);
 		}
+		indsz = caps.ndis_nind;
+	} else {
+		indsz = NDIS_HASH_INDCNT;
+	}
+	if (indsz < rxr_cnt) {
+		if_printf(sc->hn_ifp, "# of RX rings (%d) > "
+		    "RSS indirect table size %d\n", rxr_cnt, indsz);
+		rxr_cnt = indsz;
 	}
+
+	/*
+	 * NOTE:
+	 * Toeplitz is at the lowest bit, and it is prefered; so ffs(),
+	 * instead of fls(), is used here.
+	 */
+	hash_fnidx = ffs(caps.ndis_caps & NDIS_RSS_CAP_HASHFUNC_MASK);
+	if (hash_fnidx == 0) {
+		if_printf(sc->hn_ifp, "no hash functions, caps 0x%08x\n",
+		    caps.ndis_caps);
+		return (EOPNOTSUPP);
+	}
+	hash_func = 1 << (hash_fnidx - 1); /* ffs is 1-based */
+
+	if (caps.ndis_caps & NDIS_RSS_CAP_IPV4)
+		hash_types |= NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4;
+	if (caps.ndis_caps & NDIS_RSS_CAP_IPV6)
+		hash_types |= NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
+	if (caps.ndis_caps & NDIS_RSS_CAP_IPV6_EX)
+		hash_types |= NDIS_HASH_IPV6_EX | NDIS_HASH_TCP_IPV6_EX;
+	if (hash_types == 0) {
+		if_printf(sc->hn_ifp, "no hash types, caps 0x%08x\n",
+		    caps.ndis_caps);
+		return (EOPNOTSUPP);
+	}
+
+	/* Commit! */
+	sc->hn_rss_ind_size = indsz;
+	sc->hn_rss_hash = hash_func | hash_types;
+	*rxr_cnt0 = rxr_cnt;
 	return (0);
 }
 
@@ -1034,7 +1090,7 @@ hn_rndis_conf_rss(struct hn_softc *sc, u
 {
 	struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
 	struct ndis_rss_params *prm = &rss->rss_params;
-	int error;
+	int error, rss_size;
 
 	/*
 	 * Only NDIS 6.20+ is supported:
@@ -1044,21 +1100,29 @@ hn_rndis_conf_rss(struct hn_softc *sc, u
 	KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_20,
 	    ("NDIS 6.20+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
 
+	/* XXX only one can be specified through, popcnt? */
+	KASSERT((sc->hn_rss_hash & NDIS_HASH_FUNCTION_MASK), ("no hash func"));
+	KASSERT((sc->hn_rss_hash & NDIS_HASH_TYPE_MASK), ("no hash types"));
+	KASSERT(sc->hn_rss_ind_size > 0, ("no indirect table size"));
+
+	if (bootverbose) {
+		if_printf(sc->hn_ifp, "RSS indirect table size %d, "
+		    "hash 0x%08x\n", sc->hn_rss_ind_size, sc->hn_rss_hash);
+	}
+
 	/*
 	 * NOTE:
 	 * DO NOT whack rss_key and rss_ind, which are setup by the caller.
 	 */
 	memset(prm, 0, sizeof(*prm));
+	rss_size = NDIS_RSSPRM_TOEPLITZ_SIZE(sc->hn_rss_ind_size);
 
 	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);
+	prm->ndis_hdr.ndis_size = rss_size;
 	prm->ndis_flags = flags;
-	prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
-	    NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
-	    NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
-	/* TODO: Take ndis_rss_caps.ndis_nind into account */
-	prm->ndis_indsize = sizeof(rss->rss_ind);
+	prm->ndis_hash = sc->hn_rss_hash;
+	prm->ndis_indsize = sizeof(rss->rss_ind[0]) * sc->hn_rss_ind_size;
 	prm->ndis_indoffset =
 	    __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
 	prm->ndis_keysize = sizeof(rss->rss_key);
@@ -1066,7 +1130,7 @@ hn_rndis_conf_rss(struct hn_softc *sc, u
 	    __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
 
 	error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
-	    rss, sizeof(*rss));
+	    rss, rss_size);
 	if (error) {
 		if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
 	} else {

Modified: stable/10/sys/dev/hyperv/netvsc/ndis.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/ndis.h	Fri Nov 11 04:39:02 2016	(r308501)
+++ stable/10/sys/dev/hyperv/netvsc/ndis.h	Fri Nov 11 05:07:25 2016	(r308502)
@@ -57,6 +57,10 @@
 #define	NDIS_HASH_TCP_IPV6		0x00001000
 #define	NDIS_HASH_TCP_IPV6_EX		0x00002000
 
+/* Hash description for use with printf(9) %b identifier. */
+#define	NDIS_HASH_BITS			\
+	"\20\1TOEPLITZ\11IP4\12TCP4\13IP6\14IP6EX\15TCP6\16TCP6EX"
+
 #define	NDIS_HASH_KEYSIZE_TOEPLITZ	40
 #define	NDIS_HASH_INDCNT		128
 
@@ -142,7 +146,7 @@ struct ndis_offload_params {
  */
 struct ndis_rss_caps {
 	struct ndis_object_hdr		ndis_hdr;
-	uint32_t			ndis_flags;	/* NDIS_RSS_CAP_ */
+	uint32_t			ndis_caps;	/* NDIS_RSS_CAP_ */
 	uint32_t			ndis_nmsi;	/* # of MSIs */
 	uint32_t			ndis_nrxr;	/* # of RX rings */
 	/* NDIS >= 6.30 */
@@ -165,7 +169,8 @@ struct ndis_rss_caps {
 #define	NDIS_RSS_CAP_IPV4		0x00000100
 #define	NDIS_RSS_CAP_IPV6		0x00000200
 #define	NDIS_RSS_CAP_IPV6_EX		0x00000400
-#define	NDIS_RSS_CAP_HASH_TOEPLITZ	0x00000001
+#define	NDIS_RSS_CAP_HASH_TOEPLITZ	NDIS_HASH_FUNCTION_TOEPLITZ
+#define	NDIS_RSS_CAP_HASHFUNC_MASK	NDIS_HASH_FUNCTION_MASK
 
 /*
  * OID_GEN_RECEIVE_SCALE_PARAMETERS
@@ -209,6 +214,9 @@ struct ndis_rssprm_toeplitz {
 	uint32_t			rss_ind[NDIS_HASH_INDCNT];
 };
 
+#define	NDIS_RSSPRM_TOEPLITZ_SIZE(nind)	\
+	__offsetof(struct ndis_rssprm_toeplitz, rss_ind[nind])
+
 /*
  * OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES
  * ndis_type: NDIS_OBJTYPE_OFFLOAD



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