hyperv/hn: Properly configure RSS according to RSS capabilities
MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8338
This commit is contained in:
parent
3d8102824b
commit
20b3dcf039
@ -255,6 +255,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;
|
||||
};
|
||||
|
||||
|
@ -329,6 +329,7 @@ static int hn_hwassist_sysctl(SYSCTL_HANDLER_ARGS);
|
||||
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 *);
|
||||
@ -770,6 +771,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");
|
||||
@ -2478,6 +2484,20 @@ back:
|
||||
return (error);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -3642,6 +3662,10 @@ hn_synth_attach(struct hn_softc *sc, int mtu)
|
||||
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.
|
||||
*/
|
||||
@ -3716,7 +3740,6 @@ hn_synth_attach(struct hn_softc *sc, int mtu)
|
||||
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;
|
||||
|
@ -747,13 +747,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);
|
||||
@ -792,18 +793,73 @@ hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1033,7 +1089,7 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags)
|
||||
{
|
||||
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:
|
||||
@ -1043,21 +1099,29 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags)
|
||||
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);
|
||||
@ -1065,7 +1129,7 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags)
|
||||
__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 {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user