Author: sephe
Date: Wed Oct 19 08:32:24 2016
New Revision: 307620
URL: https://svnweb.freebsd.org/changeset/base/307620

Log:
  MFC 306936-306939
  
  306936
      hyperv/hn: Fix checksum offload settings
  
      The _correct_ way to identify the supported checksum offloading and
      TSO parameters is to query OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8088
  
  306937
      hyperv/hn: Fix if_hw_tsomax setup.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8089
  
  306938
      hyperv/hn: Generalize RSS capabilities query.
  
      - Support NDIS < 6.30.
      - Stringent response checks.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8090
  
  306939
      hyperv/hn: Suffix NDIS offload size with NDIS version.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D8091

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/if_hnvar.h
  stable/10/sys/dev/hyperv/netvsc/ndis.h
  stable/10/sys/net/rndis.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        Wed Oct 19 08:23:54 
2016        (r307619)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h        Wed Oct 19 08:32:24 
2016        (r307620)
@@ -245,6 +245,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: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Wed Oct 19 
08:23:54 2016        (r307619)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Wed Oct 19 
08:32:24 2016        (r307620)
@@ -232,7 +232,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");
 
@@ -340,6 +340,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 *);
@@ -535,7 +536,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);
@@ -736,18 +736,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);
        }
 
@@ -1692,6 +1690,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)
@@ -2939,6 +2938,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;
@@ -3444,7 +3471,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: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c   Wed Oct 19 08:23:54 
2016        (r307619)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c   Wed Oct 19 08:32:24 
2016        (r307620)
@@ -40,6 +40,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>
@@ -69,6 +71,18 @@ __FBSDID("$FreeBSD$");
 
 #define HN_RNDIS_XFER_SIZE             2048
 
+#define HN_NDIS_TXCSUM_CAP_IP4         \
+       (NDIS_TXCSUM_CAP_IP4 | NDIS_TXCSUM_CAP_IP4OPT)
+#define HN_NDIS_TXCSUM_CAP_TCP4                \
+       (NDIS_TXCSUM_CAP_TCP4 | NDIS_TXCSUM_CAP_TCP4OPT)
+#define HN_NDIS_TXCSUM_CAP_TCP6                \
+       (NDIS_TXCSUM_CAP_TCP6 | NDIS_TXCSUM_CAP_TCP6OPT | \
+        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
  */
@@ -79,9 +93,14 @@ static void hv_rf_receive_data(struct hn
 
 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
     const void *idata, size_t idlen, void *odata, size_t *odlen0);
+static int hn_rndis_query2(struct hn_softc *sc, uint32_t oid,
+    const void *idata, size_t idlen, void *odata, size_t *odlen0,
+    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);
 
 static __inline uint32_t
 hn_rndis_rid(struct hn_softc *sc)
@@ -625,6 +644,15 @@ static int
 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
     const void *idata, size_t idlen, void *odata, size_t *odlen0)
 {
+
+       return (hn_rndis_query2(sc, oid, idata, idlen, odata, odlen0, *odlen0));
+}
+
+static int
+hn_rndis_query2(struct hn_softc *sc, uint32_t oid,
+    const void *idata, size_t idlen, void *odata, size_t *odlen0,
+    size_t min_odlen)
+{
        struct rndis_query_req *req;
        const struct rndis_query_comp *comp;
        struct vmbus_xact *xact;
@@ -662,7 +690,7 @@ hn_rndis_query(struct hn_softc *sc, uint
                memcpy(req + 1, idata, idlen);
        }
 
-       comp_len = sizeof(*comp) + odlen;
+       comp_len = sizeof(*comp) + min_odlen;
        comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
            REMOTE_NDIS_QUERY_CMPLT);
        if (comp == NULL) {
@@ -718,26 +746,44 @@ hn_rndis_get_rsscaps(struct hn_softc *sc
        size_t caps_len;
        int error;
 
-       /*
-        * Only NDIS 6.30+ is supported.
-        */
-       KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
-           ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
        *rxr_cnt = 0;
 
        memset(&in, 0, sizeof(in));
        in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
-       in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
-       in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
+       if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) {
+               in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_1;
+               in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE_6_0;
+       } else {
+               in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
+               in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
+       }
 
        caps_len = NDIS_RSS_CAPS_SIZE;
-       error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
-           &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
+       error = hn_rndis_query2(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
+           &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len, NDIS_RSS_CAPS_SIZE_6_0);
        if (error)
                return (error);
-       if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
-               if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
-                   caps_len);
+
+       /*
+        * Preliminary verification.
+        */
+       if (caps.ndis_hdr.ndis_type != NDIS_OBJTYPE_RSS_CAPS) {
+               if_printf(sc->hn_ifp, "invalid NDIS objtype 0x%02x\n",
+                   caps.ndis_hdr.ndis_type);
+               return (EINVAL);
+       }
+       if (caps.ndis_hdr.ndis_rev < NDIS_RSS_CAPS_REV_1) {
+               if_printf(sc->hn_ifp, "invalid NDIS objrev 0x%02x\n",
+                   caps.ndis_hdr.ndis_rev);
+               return (EINVAL);
+       }
+       if (caps.ndis_hdr.ndis_size > caps_len) {
+               if_printf(sc->hn_ifp, "invalid NDIS objsize %u, "
+                   "data size %zu\n", caps.ndis_hdr.ndis_size, caps_len);
+               return (EINVAL);
+       } else if (caps.ndis_hdr.ndis_size < NDIS_RSS_CAPS_SIZE_6_0) {
+               if_printf(sc->hn_ifp, "invalid NDIS objsize %u\n",
+                   caps.ndis_hdr.ndis_size);
                return (EINVAL);
        }
 
@@ -747,7 +793,7 @@ hn_rndis_get_rsscaps(struct hn_softc *sc
        }
        *rxr_cnt = caps.ndis_nrxr;
 
-       if (caps_len == NDIS_RSS_CAPS_SIZE) {
+       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);
@@ -807,12 +853,19 @@ 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;
+       uint32_t caps = 0;
        size_t paramsz;
-       int error;
+       int error, tso_maxsz, tso_minsg;
+
+       error = hn_rndis_query_hwcaps(sc, &hwcaps);
+       if (error) {
+               if_printf(sc->hn_ifp, "hwcaps query failed: %d\n", error);
+               return (error);
+       }
 
        /* NOTE: 0 means "no change" */
        memset(&params, 0, sizeof(params));
@@ -827,18 +880,136 @@ hn_rndis_conf_offload(struct hn_softc *s
        }
        params.ndis_hdr.ndis_size = paramsz;
 
-       caps = HN_CAP_IPCS | HN_CAP_TCP4CS | HN_CAP_TCP6CS;
-       params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
-       params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
-       params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
-       if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
-               caps |= HN_CAP_UDP4CS | HN_CAP_UDP6CS;
-               params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
-               params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
-       }
-       caps |= HN_CAP_TSO4;
-       params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
-       /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
+       /*
+        * 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;
+
+               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
+       }
+       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 */
+       if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_IP4) ==
+           HN_NDIS_TXCSUM_CAP_IP4) {
+               caps |= HN_CAP_IPCS;
+               params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TX;
+       }
+       if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_IP4) {
+               if (params.ndis_ip4csum == NDIS_OFFLOAD_PARAM_TX)
+                       params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
+               else
+                       params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_RX;
+       }
+
+       /* TCP4 checksum */
+       if ((hwcaps.ndis_csum.ndis_ip4_txcsum & HN_NDIS_TXCSUM_CAP_TCP4) ==
+           HN_NDIS_TXCSUM_CAP_TCP4) {
+               caps |= HN_CAP_TCP4CS;
+               params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TX;
+       }
+       if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_TCP4) {
+               if (params.ndis_tcp4csum == NDIS_OFFLOAD_PARAM_TX)
+                       params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
+               else
+                       params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_RX;
+       }
+
+       /* UDP4 checksum */
+       if (hwcaps.ndis_csum.ndis_ip4_txcsum & NDIS_TXCSUM_CAP_UDP4) {
+               caps |= HN_CAP_UDP4CS;
+               params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TX;
+       }
+       if (hwcaps.ndis_csum.ndis_ip4_rxcsum & NDIS_RXCSUM_CAP_UDP4) {
+               if (params.ndis_udp4csum == NDIS_OFFLOAD_PARAM_TX)
+                       params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
+               else
+                       params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_RX;
+       }
+
+       /* TCP6 checksum */
+       if ((hwcaps.ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_TCP6) ==
+           HN_NDIS_TXCSUM_CAP_TCP6) {
+               caps |= HN_CAP_TCP6CS;
+               params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TX;
+       }
+       if (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_TCP6) {
+               if (params.ndis_tcp6csum == NDIS_OFFLOAD_PARAM_TX)
+                       params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
+               else
+                       params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_RX;
+       }
+
+       /* UDP6 checksum */
+       if ((hwcaps.ndis_csum.ndis_ip6_txcsum & HN_NDIS_TXCSUM_CAP_UDP6) ==
+           HN_NDIS_TXCSUM_CAP_UDP6) {
+               caps |= HN_CAP_UDP6CS;
+               params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TX;
+       }
+       if (hwcaps.ndis_csum.ndis_ip6_rxcsum & NDIS_RXCSUM_CAP_UDP6) {
+               if (params.ndis_udp6csum == NDIS_OFFLOAD_PARAM_TX)
+                       params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
+               else
+                       params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_RX;
+       }
+
+       if (bootverbose) {
+               if_printf(sc->hn_ifp, "offload csum: "
+                   "ip4 %u, tcp4 %u, udp4 %u, tcp6 %u, udp6 %u\n",
+                   params.ndis_ip4csum,
+                   params.ndis_tcp4csum,
+                   params.ndis_udp4csum,
+                   params.ndis_tcp6csum,
+                   params.ndis_udp6csum);
+               if_printf(sc->hn_ifp, "offload lsov2: ip4 %u, ip6 %u\n",
+                   params.ndis_lsov2_ip4,
+                   params.ndis_lsov2_ip6);
+       }
 
        error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, &params, paramsz);
        if (error) {
@@ -995,8 +1166,92 @@ hn_rndis_halt(struct hn_softc *sc)
        return (0);
 }
 
+static int
+hn_rndis_query_hwcaps(struct hn_softc *sc, struct ndis_offload *caps)
+{
+       struct ndis_offload in;
+       size_t caps_len, size;
+       int error;
+
+       memset(&in, 0, sizeof(in));
+       in.ndis_hdr.ndis_type = NDIS_OBJTYPE_OFFLOAD;
+       if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
+               in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_3;
+               size = NDIS_OFFLOAD_SIZE;
+       } else if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_1) {
+               in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_2;
+               size = NDIS_OFFLOAD_SIZE_6_1;
+       } else {
+               in.ndis_hdr.ndis_rev = NDIS_OFFLOAD_REV_1;
+               size = NDIS_OFFLOAD_SIZE_6_0;
+       }
+       in.ndis_hdr.ndis_size = size;
+
+       caps_len = NDIS_OFFLOAD_SIZE;
+       error = hn_rndis_query2(sc, OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES,
+           &in, size, caps, &caps_len, NDIS_OFFLOAD_SIZE_6_0);
+       if (error)
+               return (error);
+
+       /*
+        * Preliminary verification.
+        */
+       if (caps->ndis_hdr.ndis_type != NDIS_OBJTYPE_OFFLOAD) {
+               if_printf(sc->hn_ifp, "invalid NDIS objtype 0x%02x\n",
+                   caps->ndis_hdr.ndis_type);
+               return (EINVAL);
+       }
+       if (caps->ndis_hdr.ndis_rev < NDIS_OFFLOAD_REV_1) {
+               if_printf(sc->hn_ifp, "invalid NDIS objrev 0x%02x\n",
+                   caps->ndis_hdr.ndis_rev);
+               return (EINVAL);
+       }
+       if (caps->ndis_hdr.ndis_size > caps_len) {
+               if_printf(sc->hn_ifp, "invalid NDIS objsize %u, "
+                   "data size %zu\n", caps->ndis_hdr.ndis_size, caps_len);
+               return (EINVAL);
+       } else if (caps->ndis_hdr.ndis_size < NDIS_OFFLOAD_SIZE_6_0) {
+               if_printf(sc->hn_ifp, "invalid NDIS objsize %u\n",
+                   caps->ndis_hdr.ndis_size);
+               return (EINVAL);
+       }
+
+       if (bootverbose) {
+               /*
+                * NOTE:
+                * caps->ndis_hdr.ndis_size MUST be checked before accessing
+                * NDIS 6.1+ specific fields.
+                */
+               if_printf(sc->hn_ifp, "hwcaps rev %u\n",
+                   caps->ndis_hdr.ndis_rev);
+
+               if_printf(sc->hn_ifp, "hwcaps csum: "
+                   "ip4 tx 0x%x/0x%x rx 0x%x/0x%x, "
+                   "ip6 tx 0x%x/0x%x rx 0x%x/0x%x\n",
+                   caps->ndis_csum.ndis_ip4_txcsum,
+                   caps->ndis_csum.ndis_ip4_txenc,
+                   caps->ndis_csum.ndis_ip4_rxcsum,
+                   caps->ndis_csum.ndis_ip4_rxenc,
+                   caps->ndis_csum.ndis_ip6_txcsum,
+                   caps->ndis_csum.ndis_ip6_txenc,
+                   caps->ndis_csum.ndis_ip6_rxcsum,
+                   caps->ndis_csum.ndis_ip6_rxenc);
+               if_printf(sc->hn_ifp, "hwcaps lsov2: "
+                   "ip4 maxsz %u minsg %u encap 0x%x, "
+                   "ip6 maxsz %u minsg %u encap 0x%x opts 0x%x\n",
+                   caps->ndis_lsov2.ndis_ip4_maxsz,
+                   caps->ndis_lsov2.ndis_ip4_minsg,
+                   caps->ndis_lsov2.ndis_ip4_encap,
+                   caps->ndis_lsov2.ndis_ip6_maxsz,
+                   caps->ndis_lsov2.ndis_ip6_minsg,
+                   caps->ndis_lsov2.ndis_ip6_encap,
+                   caps->ndis_lsov2.ndis_ip6_opts);
+       }
+       return (0);
+}
+
 int
-hn_rndis_attach(struct hn_softc *sc)
+hn_rndis_attach(struct hn_softc *sc, int mtu)
 {
        int error;
 
@@ -1011,7 +1266,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: stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/if_hnvar.h  Wed Oct 19 08:23:54 2016        
(r307619)
+++ stable/10/sys/dev/hyperv/netvsc/if_hnvar.h  Wed Oct 19 08:32:24 2016        
(r307620)
@@ -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 *,

Modified: stable/10/sys/dev/hyperv/netvsc/ndis.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/ndis.h      Wed Oct 19 08:23:54 2016        
(r307619)
+++ stable/10/sys/dev/hyperv/netvsc/ndis.h      Wed Oct 19 08:32:24 2016        
(r307620)
@@ -59,6 +59,7 @@
 #define        NDIS_OBJTYPE_DEFAULT            0x80
 #define        NDIS_OBJTYPE_RSS_CAPS           0x88
 #define        NDIS_OBJTYPE_RSS_PARAMS         0x89
+#define        NDIS_OBJTYPE_OFFLOAD            0xa7
 
 struct ndis_object_hdr {
        uint8_t                 ndis_type;      /* NDIS_OBJTYPE_ */
@@ -205,6 +206,129 @@ struct ndis_rssprm_toeplitz {
 };
 
 /*
+ * OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES
+ * ndis_type: NDIS_OBJTYPE_OFFLOAD
+ */
+
+#define        NDIS_OFFLOAD_ENCAP_NONE         0x0000
+#define        NDIS_OFFLOAD_ENCAP_NULL         0x0001
+#define        NDIS_OFFLOAD_ENCAP_8023         0x0002
+#define        NDIS_OFFLOAD_ENCAP_8023PQ       0x0004
+#define        NDIS_OFFLOAD_ENCAP_8023PQ_OOB   0x0008
+#define        NDIS_OFFLOAD_ENCAP_RFC1483      0x0010
+
+struct ndis_csum_offload {
+       uint32_t                        ndis_ip4_txenc; /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ip4_txcsum;
+#define        NDIS_TXCSUM_CAP_IP4OPT          0x001
+#define        NDIS_TXCSUM_CAP_TCP4OPT         0x004
+#define        NDIS_TXCSUM_CAP_TCP4            0x010
+#define        NDIS_TXCSUM_CAP_UDP4            0x040
+#define        NDIS_TXCSUM_CAP_IP4             0x100
+       uint32_t                        ndis_ip4_rxenc; /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ip4_rxcsum;
+#define        NDIS_RXCSUM_CAP_IP4OPT          0x001
+#define        NDIS_RXCSUM_CAP_TCP4OPT         0x004
+#define        NDIS_RXCSUM_CAP_TCP4            0x010
+#define        NDIS_RXCSUM_CAP_UDP4            0x040
+#define        NDIS_RXCSUM_CAP_IP4             0x100
+       uint32_t                        ndis_ip6_txenc; /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ip6_txcsum;
+#define        NDIS_TXCSUM_CAP_IP6EXT          0x001
+#define        NDIS_TXCSUM_CAP_TCP6OPT         0x004
+#define        NDIS_TXCSUM_CAP_TCP6            0x010
+#define        NDIS_TXCSUM_CAP_UDP6            0x040
+       uint32_t                        ndis_ip6_rxenc; /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ip6_rxcsum;
+#define        NDIS_RXCSUM_CAP_IP6EXT          0x001
+#define        NDIS_RXCSUM_CAP_TCP6OPT         0x004
+#define        NDIS_RXCSUM_CAP_TCP6            0x010
+#define        NDIS_RXCSUM_CAP_UDP6            0x040
+};
+
+struct ndis_lsov1_offload {
+       uint32_t                        ndis_encap;     /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_maxsize;
+       uint32_t                        ndis_minsegs;
+       uint32_t                        ndis_opts;
+};
+
+struct ndis_ipsecv1_offload {
+       uint32_t                        ndis_encap;     /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ah_esp;
+       uint32_t                        ndis_xport_tun;
+       uint32_t                        ndis_ip4_opts;
+       uint32_t                        ndis_flags;
+       uint32_t                        ndis_ip4_ah;
+       uint32_t                        ndis_ip4_esp;
+};
+
+struct ndis_lsov2_offload {
+       uint32_t                        ndis_ip4_encap; /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ip4_maxsz;
+       uint32_t                        ndis_ip4_minsg;
+       uint32_t                        ndis_ip6_encap; /*NDIS_OFFLOAD_ENCAP_*/
+       uint32_t                        ndis_ip6_maxsz;
+       uint32_t                        ndis_ip6_minsg;
+       uint32_t                        ndis_ip6_opts;
+#define        NDIS_LSOV2_CAP_IP6EXT           0x001
+#define        NDIS_LSOV2_CAP_TCP6OPT          0x004
+};
+
+struct ndis_ipsecv2_offload {
+       uint32_t                        ndis_encap;     /*NDIS_OFFLOAD_ENCAP_*/
+       uint16_t                        ndis_ip6;
+       uint16_t                        ndis_ip4opt;
+       uint16_t                        ndis_ip6ext;
+       uint16_t                        ndis_ah;
+       uint16_t                        ndis_esp;
+       uint16_t                        ndis_ah_esp;
+       uint16_t                        ndis_xport;
+       uint16_t                        ndis_tun;
+       uint16_t                        ndis_xport_tun;
+       uint16_t                        ndis_lso;
+       uint16_t                        ndis_extseq;
+       uint32_t                        ndis_udp_esp;
+       uint32_t                        ndis_auth;
+       uint32_t                        ndis_crypto;
+       uint32_t                        ndis_sa_caps;
+};
+
+struct ndis_rsc_offload {
+       uint16_t                        ndis_ip4;
+       uint16_t                        ndis_ip6;
+};
+
+struct ndis_encap_offload {
+       uint32_t                        ndis_flags;
+       uint32_t                        ndis_maxhdr;
+};
+
+struct ndis_offload {
+       struct ndis_object_hdr          ndis_hdr;
+       struct ndis_csum_offload        ndis_csum;
+       struct ndis_lsov1_offload       ndis_lsov1;
+       struct ndis_ipsecv1_offload     ndis_ipsecv1;
+       struct ndis_lsov2_offload       ndis_lsov2;
+       uint32_t                        ndis_flags;
+       /* NDIS >= 6.1 */
+       struct ndis_ipsecv2_offload     ndis_ipsecv2;
+       /* NDIS >= 6.30 */
+       struct ndis_rsc_offload         ndis_rsc;
+       struct ndis_encap_offload       ndis_encap_gre;
+};
+
+#define        NDIS_OFFLOAD_SIZE               sizeof(struct ndis_offload)
+#define        NDIS_OFFLOAD_SIZE_6_0           \
+       __offsetof(struct ndis_offload, ndis_ipsecv2)
+#define        NDIS_OFFLOAD_SIZE_6_1           \
+       __offsetof(struct ndis_offload, ndis_rsc)
+
+#define        NDIS_OFFLOAD_REV_1              1       /* NDIS 6.0 */
+#define        NDIS_OFFLOAD_REV_2              2       /* NDIS 6.1 */
+#define        NDIS_OFFLOAD_REV_3              3       /* NDIS 6.30 */
+
+/*
  * Per-packet-info
  */
 

Modified: stable/10/sys/net/rndis.h
==============================================================================
--- stable/10/sys/net/rndis.h   Wed Oct 19 08:23:54 2016        (r307619)
+++ stable/10/sys/net/rndis.h   Wed Oct 19 08:32:24 2016        (r307620)
@@ -87,6 +87,7 @@
 #define        OID_802_3_XMIT_LATE_COLLISIONS  0x01020207
 
 #define        OID_TCP_OFFLOAD_PARAMETERS      0xFC01020C
+#define        OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES   0xFC01020D
 
 #define        RNDIS_MEDIUM_802_3              0x00000000
 
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to