diff options
Diffstat (limited to 'sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c')
-rw-r--r-- | sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c | 142 |
1 files changed, 135 insertions, 7 deletions
diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index fe68872..7f541be 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -325,6 +325,8 @@ static int hn_rx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); static int hn_tx_stat_ulong_sysctl(SYSCTL_HANDLER_ARGS); static int hn_tx_conf_int_sysctl(SYSCTL_HANDLER_ARGS); static int hn_ndis_version_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_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 *); @@ -391,6 +393,62 @@ hn_get_txswq_depth(const struct hn_tx_ring *txr) } static int +hn_rss_reconfig(struct hn_softc *sc) +{ + int error; + + HN_LOCK_ASSERT(sc); + + /* + * Disable RSS first. + * + * NOTE: + * Direct reconfiguration by setting the UNCHG flags does + * _not_ work properly. + */ + if (bootverbose) + if_printf(sc->hn_ifp, "disable RSS\n"); + error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_DISABLE); + if (error) { + if_printf(sc->hn_ifp, "RSS disable failed\n"); + return (error); + } + + /* + * Reenable the RSS w/ the updated RSS key or indirect + * table. + */ + if (bootverbose) + if_printf(sc->hn_ifp, "reconfig RSS\n"); + error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); + if (error) { + if_printf(sc->hn_ifp, "RSS reconfig failed\n"); + return (error); + } + return (0); +} + +static void +hn_rss_ind_fixup(struct hn_softc *sc, int nchan) +{ + struct ndis_rssprm_toeplitz *rss = &sc->hn_rss; + int i; + + /* + * Check indirect table to make sure that all channels in it + * can be used. + */ + for (i = 0; i < NDIS_HASH_INDCNT; ++i) { + if (rss->rss_ind[i] >= nchan) { + if_printf(sc->hn_ifp, + "RSS indirect table %d fixup: %u -> %d\n", + i, rss->rss_ind[i], nchan - 1); + rss->rss_ind[i] = nchan - 1; + } + } +} + +static int hn_ifmedia_upd(struct ifnet *ifp __unused) { @@ -583,6 +641,12 @@ netvsc_attach(device_t dev) SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "ndis_version", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0, hn_ndis_version_sysctl, "A", "NDIS version"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_key", + CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, + hn_rss_key_sysctl, "IU", "RSS key"); + SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rss_ind", + CTLTYPE_OPAQUE | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0, + hn_rss_ind_sysctl, "IU", "RSS indirect table"); /* * Setup the ifmedia, which has been initialized earlier. @@ -2031,6 +2095,51 @@ hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS) } static int +hn_rss_key_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct hn_softc *sc = arg1; + int error; + + HN_LOCK(sc); + + error = SYSCTL_OUT(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); + if (error || req->newptr == NULL) + goto back; + + error = SYSCTL_IN(req, sc->hn_rss.rss_key, sizeof(sc->hn_rss.rss_key)); + if (error) + goto back; + + error = hn_rss_reconfig(sc); +back: + HN_UNLOCK(sc); + return (error); +} + +static int +hn_rss_ind_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct hn_softc *sc = arg1; + int error; + + HN_LOCK(sc); + + error = SYSCTL_OUT(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); + if (error || req->newptr == NULL) + goto back; + + error = SYSCTL_IN(req, sc->hn_rss.rss_ind, sizeof(sc->hn_rss.rss_ind)); + if (error) + goto back; + + hn_rss_ind_fixup(sc, sc->hn_rx_ring_inuse); + error = hn_rss_reconfig(sc); +back: + HN_UNLOCK(sc); + return (error); +} + +static int hn_check_iplen(const struct mbuf *m, int hoff) { const struct ip *ip; @@ -3159,15 +3268,34 @@ hn_synth_attach(struct hn_softc *sc, int mtu) * are allocated. */ - /* Setup default RSS key. */ - memcpy(rss->rss_key, hn_rss_key_default, sizeof(rss->rss_key)); + if (!device_is_attached(sc->hn_dev)) { + /* + * Setup default RSS key and indirect table for the + * attach DEVMETHOD. They can be altered later on, + * so don't mess them up once this interface is attached. + */ + if (bootverbose) { + if_printf(sc->hn_ifp, "setup default RSS key and " + "indirect table\n"); + } + + /* 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; + /* 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; + } else { + /* + * # of usable channels may be changed, so we have to + * make sure that all entries in RSS indirect table + * are valid. + */ + hn_rss_ind_fixup(sc, nchan); + } - error = hn_rndis_conf_rss(sc); + error = hn_rndis_conf_rss(sc, NDIS_RSS_FLAG_NONE); if (error) { /* * Failed to configure RSS key or indirect table; only |