Author: sephe
Date: Mon Oct 10 05:50:01 2016
New Revision: 306937
URL: https://svnweb.freebsd.org/changeset/base/306937

Log:
  hyperv/hn: Fix if_hw_tsomax setup.
  
  MFC after:    1 week
  Sponsored by: Microsoft
  Differential Revision:        https://reviews.freebsd.org/D8089

Modified:
  head/sys/dev/hyperv/netvsc/hv_net_vsc.h
  head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  head/sys/dev/hyperv/netvsc/if_hnvar.h

Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_net_vsc.h     Mon Oct 10 05:41:39 2016        
(r306936)
+++ head/sys/dev/hyperv/netvsc/hv_net_vsc.h     Mon Oct 10 05:50:01 2016        
(r306937)
@@ -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;
 };

Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Mon Oct 10 05:41:39 
2016        (r306936)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Mon Oct 10 05:50:01 
2016        (r306937)
@@ -230,7 +230,7 @@ SYSCTL_INT(_hw_hn, OID_AUTO, trust_hosti
     "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 *,
 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, 
 
                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)
@@ -2919,6 +2918,34 @@ hn_set_chim_size(struct hn_softc *sc, in
 }
 
 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)
 {
        uint64_t csum_assist;
@@ -3424,7 +3451,7 @@ hn_synth_attach(struct hn_softc *sc, int
        /*
         * Attach RNDIS _after_ NVS is attached.
         */
-       error = hn_rndis_attach(sc);
+       error = hn_rndis_attach(sc, mtu);
        if (error)
                return (error);
 

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Mon Oct 10 05:41:39 
2016        (r306936)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Mon Oct 10 05:50:01 
2016        (r306937)
@@ -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_sof
     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 @@ done:
 }
 
 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 *s
        }
        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_ip6_encap & NDIS_OFFLOAD_ENCAP_8023) {
+
+               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) &&
+           (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 *s
 }
 
 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);
 }
 

Modified: head/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hnvar.h       Mon Oct 10 05:41:39 2016        
(r306936)
+++ head/sys/dev/hyperv/netvsc/if_hnvar.h       Mon Oct 10 05:50:01 2016        
(r306937)
@@ -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 *,
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to