hyperv/hn: Fix if_hw_tsomax setup.

MFC after:	1 week
Sponsored by:	Microsoft
Differential Revision:	https://reviews.freebsd.org/D8089
This commit is contained in:
Sepherosa Ziehau 2016-10-10 05:50:01 +00:00
parent 65ca331080
commit c21d553cfa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=306937
4 changed files with 95 additions and 22 deletions

View File

@ -244,6 +244,8 @@ struct hn_softc {
uint32_t hn_rndis_rid;
uint32_t hn_ndis_ver;
int hn_ndis_tso_szmax;
int hn_ndis_tso_sgmin;
struct ndis_rssprm_toeplitz hn_rss;
};

View File

@ -230,7 +230,7 @@ SYSCTL_INT(_hw_hn, OID_AUTO, trust_hostip, CTLFLAG_RDTUN,
"when csum info is missing (global setting)");
/* Limit TSO burst size */
static int hn_tso_maxlen = 0;
static int hn_tso_maxlen = IP_MAXPACKET;
SYSCTL_INT(_hw_hn, OID_AUTO, tso_maxlen, CTLFLAG_RDTUN,
&hn_tso_maxlen, 0, "TSO burst limit");
@ -338,6 +338,7 @@ 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);
static void hn_set_chim_size(struct hn_softc *, int);
static void hn_set_tso_maxsize(struct hn_softc *, int, 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 *);
@ -520,7 +521,6 @@ netvsc_attach(device_t dev)
uint32_t link_status;
struct ifnet *ifp = NULL;
int error, ring_cnt, tx_ring_cnt;
int tso_maxlen;
sc->hn_dev = dev;
sc->hn_prichan = vmbus_get_channel(dev);
@ -720,18 +720,16 @@ netvsc_attach(device_t dev)
/* Enable all available capabilities by default. */
ifp->if_capenable = ifp->if_capabilities;
tso_maxlen = hn_tso_maxlen;
if (tso_maxlen <= 0 || tso_maxlen > IP_MAXPACKET)
tso_maxlen = IP_MAXPACKET;
ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
ifp->if_hw_tsomax = tso_maxlen -
(ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
if (ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) {
hn_set_tso_maxsize(sc, hn_tso_maxlen, ETHERMTU);
ifp->if_hw_tsomaxsegcount = HN_TX_DATA_SEGCNT_MAX;
ifp->if_hw_tsomaxsegsize = PAGE_SIZE;
}
ether_ifattach(ifp, eaddr);
if (bootverbose) {
if_printf(ifp, "TSO: %u/%u/%u\n", ifp->if_hw_tsomax,
if ((ifp->if_capabilities & (IFCAP_TSO6 | IFCAP_TSO4)) && bootverbose) {
if_printf(ifp, "TSO segcnt %u segsz %u\n",
ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
}
@ -1672,6 +1670,7 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
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)
@ -2918,6 +2917,34 @@ hn_set_chim_size(struct hn_softc *sc, int chim_size)
sc->hn_tx_ring[i].hn_chim_size = chim_size;
}
static void
hn_set_tso_maxsize(struct hn_softc *sc, int tso_maxlen, int mtu)
{
struct ifnet *ifp = sc->hn_ifp;
int tso_minlen;
if ((ifp->if_capabilities & (IFCAP_TSO4 | IFCAP_TSO6)) == 0)
return;
KASSERT(sc->hn_ndis_tso_sgmin >= 2,
("invalid NDIS tso sgmin %d", sc->hn_ndis_tso_sgmin));
tso_minlen = sc->hn_ndis_tso_sgmin * mtu;
KASSERT(sc->hn_ndis_tso_szmax >= tso_minlen &&
sc->hn_ndis_tso_szmax <= IP_MAXPACKET,
("invalid NDIS tso szmax %d", sc->hn_ndis_tso_szmax));
if (tso_maxlen < tso_minlen)
tso_maxlen = tso_minlen;
else if (tso_maxlen > IP_MAXPACKET)
tso_maxlen = IP_MAXPACKET;
if (tso_maxlen > sc->hn_ndis_tso_szmax)
tso_maxlen = sc->hn_ndis_tso_szmax;
ifp->if_hw_tsomax = tso_maxlen - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
if (bootverbose)
if_printf(ifp, "TSO size max %u\n", ifp->if_hw_tsomax);
}
static void
hn_fixup_tx_data(struct hn_softc *sc)
{
@ -3424,7 +3451,7 @@ hn_synth_attach(struct hn_softc *sc, int mtu)
/*
* Attach RNDIS _after_ NVS is attached.
*/
error = hn_rndis_attach(sc);
error = hn_rndis_attach(sc, mtu);
if (error)
return (error);

View File

@ -39,6 +39,8 @@ __FBSDID("$FreeBSD$");
#include <net/if_var.h>
#include <net/ethernet.h>
#include <net/rndis.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <machine/atomic.h>
#include <sys/sema.h>
@ -77,6 +79,8 @@ __FBSDID("$FreeBSD$");
NDIS_TXCSUM_CAP_IP6EXT)
#define HN_NDIS_TXCSUM_CAP_UDP6 \
(NDIS_TXCSUM_CAP_UDP6 | NDIS_TXCSUM_CAP_IP6EXT)
#define HN_NDIS_LSOV2_CAP_IP6 \
(NDIS_LSOV2_CAP_IP6EXT | NDIS_LSOV2_CAP_TCP6OPT)
/*
* Forward declarations
@ -93,7 +97,7 @@ static int hn_rndis_query2(struct hn_softc *sc, uint32_t oid,
size_t min_odlen);
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_conf_offload(struct hn_softc *sc, int mtu);
static int hn_rndis_query_hwcaps(struct hn_softc *sc,
struct ndis_offload *caps);
@ -830,13 +834,13 @@ 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)
hn_rndis_conf_offload(struct hn_softc *sc, int mtu)
{
struct ndis_offload hwcaps;
struct ndis_offload_params params;
uint32_t caps = 0;
size_t paramsz;
int error;
int error, tso_maxsz, tso_minsg;
error = hn_rndis_query_hwcaps(sc, &hwcaps);
if (error) {
@ -857,18 +861,58 @@ hn_rndis_conf_offload(struct hn_softc *sc)
}
params.ndis_hdr.ndis_size = paramsz;
/* TSO */
/*
* TSO4/TSO6 setup.
*/
tso_maxsz = IP_MAXPACKET;
tso_minsg = 2;
if (hwcaps.ndis_lsov2.ndis_ip4_encap & NDIS_OFFLOAD_ENCAP_8023) {
caps |= HN_CAP_TSO4;
params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
/* TODO: tso_max */
if (hwcaps.ndis_lsov2.ndis_ip4_maxsz < tso_maxsz)
tso_maxsz = hwcaps.ndis_lsov2.ndis_ip4_maxsz;
if (hwcaps.ndis_lsov2.ndis_ip4_minsg > tso_minsg)
tso_minsg = hwcaps.ndis_lsov2.ndis_ip4_minsg;
}
if (hwcaps.ndis_lsov2.ndis_ip6_encap & NDIS_OFFLOAD_ENCAP_8023) {
if ((hwcaps.ndis_lsov2.ndis_ip6_encap & NDIS_OFFLOAD_ENCAP_8023) &&
(hwcaps.ndis_lsov2.ndis_ip6_opts & HN_NDIS_LSOV2_CAP_IP6) ==
HN_NDIS_LSOV2_CAP_IP6) {
#ifdef notyet
caps |= HN_CAP_TSO6;
params.ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON;
if (hwcaps.ndis_lsov2.ndis_ip6_maxsz < tso_maxsz)
tso_maxsz = hwcaps.ndis_lsov2.ndis_ip6_maxsz;
if (hwcaps.ndis_lsov2.ndis_ip6_minsg > tso_minsg)
tso_minsg = hwcaps.ndis_lsov2.ndis_ip6_minsg;
#endif
/* TODO: tso_max */
}
sc->hn_ndis_tso_szmax = 0;
sc->hn_ndis_tso_sgmin = 0;
if (caps & (HN_CAP_TSO4 | HN_CAP_TSO6)) {
KASSERT(tso_maxsz <= IP_MAXPACKET,
("invalid NDIS TSO maxsz %d", tso_maxsz));
KASSERT(tso_minsg >= 2,
("invalid NDIS TSO minsg %d", tso_minsg));
if (tso_maxsz < tso_minsg * mtu) {
if_printf(sc->hn_ifp, "invalid NDIS TSO config: "
"maxsz %d, minsg %d, mtu %d; "
"disable TSO4 and TSO6\n",
tso_maxsz, tso_minsg, mtu);
caps &= ~(HN_CAP_TSO4 | HN_CAP_TSO6);
params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_OFF;
params.ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_OFF;
} else {
sc->hn_ndis_tso_szmax = tso_maxsz;
sc->hn_ndis_tso_sgmin = tso_minsg;
if (bootverbose) {
if_printf(sc->hn_ifp, "NDIS TSO "
"szmax %d sgmin %d\n",
sc->hn_ndis_tso_szmax,
sc->hn_ndis_tso_sgmin);
}
}
}
/* IPv4 checksum */
@ -1186,7 +1230,7 @@ hn_rndis_query_hwcaps(struct hn_softc *sc, struct ndis_offload *caps)
}
int
hn_rndis_attach(struct hn_softc *sc)
hn_rndis_attach(struct hn_softc *sc, int mtu)
{
int error;
@ -1201,7 +1245,7 @@ hn_rndis_attach(struct hn_softc *sc)
* Configure NDIS offload settings.
* XXX no offloading, if error happened?
*/
hn_rndis_conf_offload(sc);
hn_rndis_conf_offload(sc, mtu);
return (0);
}

View File

@ -117,7 +117,7 @@ struct rndis_packet_msg;
uint32_t hn_chim_alloc(struct hn_softc *sc);
void hn_chim_free(struct hn_softc *sc, uint32_t chim_idx);
int hn_rndis_attach(struct hn_softc *sc);
int hn_rndis_attach(struct hn_softc *sc, int mtu);
void hn_rndis_detach(struct hn_softc *sc);
int hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags);
void *hn_rndis_pktinfo_append(struct rndis_packet_msg *,