Author: sephe
Date: Thu Oct 13 08:47:51 2016
New Revision: 307206
URL: https://svnweb.freebsd.org/changeset/base/307206

Log:
  MFC 305724,305725,305727-305730,305760,305761,305763,305788
  
  305724
      hyperv/hn: Rename RXBUF connect/disconnect functions.
  
      Minor cleanup and wording in error messages.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7823
  
  305725
      hyperv/hn: Rename chimney sending buffer connect/disconnect functions.
  
      Minor cleanup and wording in error messages.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7825
  
  305727
      hyperv/hn: Function rename.
  
      - Minor style changes.
      - Nuke unnecessary indirection.
      - Nuke unapplied comment.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7827
  
  305728
      hyperv/hn: Reorganize sub-channel allocation.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7829
  
  305729
      hyperv/hn: Reorganize RNDIS attach
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7830
  
  305730
      hyperv/hn: Pull ether address and link status extraction up.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7831
  
  305760
      hyperv/hn: Reorganize channel attach/detach code.
  
      This paves the way for further attach/detach code reorganization.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7858
  
  305761
      hyperv/hn: Regroup synthetic parts attach code.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7859
  
  305763
      hyperv/hn: Reorganize synthetic parts attach code.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7860
  
  305788
      hyperv/hn: Pull RSS key and indirect table setup up.
  
      This paves the way for the dynamic RSS key and indirect table setting.
  
      Sponsored by:   Microsoft
      Differential Revision:  https://reviews.freebsd.org/D7864

Modified:
  stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
  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/hv_rndis_filter.h
  stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c        Thu Oct 13 08:35:08 
2016        (r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c        Thu Oct 13 08:47:51 
2016        (r307206)
@@ -56,11 +56,10 @@ MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper
 /*
  * Forward declarations
  */
-static int  hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc);
-static int  hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *);
-static int  hv_nv_destroy_send_buffer(struct hn_softc *sc);
-static int  hv_nv_destroy_rx_buffer(struct hn_softc *sc);
-static int  hv_nv_connect_to_vsp(struct hn_softc *sc, int mtu);
+static int  hn_nvs_conn_chim(struct hn_softc *sc);
+static int  hn_nvs_conn_rxbuf(struct hn_softc *);
+static int  hn_nvs_disconn_chim(struct hn_softc *sc);
+static int  hn_nvs_disconn_rxbuf(struct hn_softc *sc);
 static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
     struct hn_softc *, struct vmbus_channel *chan,
     const void *, int);
@@ -102,7 +101,7 @@ hn_chim_alloc(struct hn_softc *sc)
        return (ret);
 }
 
-const void *
+static const void *
 hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact,
     void *req, int reqlen, size_t *resplen0, uint32_t type)
 {
@@ -153,14 +152,8 @@ hn_nvs_req_send(struct hn_softc *sc, voi
            req, reqlen, &hn_send_ctx_none));
 }
 
-/*
- * Net VSC initialize receive buffer with net VSP
- * 
- * Net VSP:  Network virtual services client, also known as the
- *     Hyper-V extensible switch and the synthetic data path.
- */
 static int 
-hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
+hn_nvs_conn_rxbuf(struct hn_softc *sc)
 {
        struct vmbus_xact *xact = NULL;
        struct hn_nvs_rxbuf_conn *conn;
@@ -187,7 +180,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
        error = vmbus_chan_gpadl_connect(sc->hn_prichan,
            sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
        if (error) {
-               if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n",
+               if_printf(sc->hn_ifp, "rxbuf gpadl conn failed: %d\n",
                    error);
                goto cleanup;
        }
@@ -211,7 +204,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
        resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len,
            HN_NVS_TYPE_RXBUF_CONNRESP);
        if (resp == NULL) {
-               if_printf(sc->hn_ifp, "exec rxbuf conn failed\n");
+               if_printf(sc->hn_ifp, "exec nvs rxbuf conn failed\n");
                error = EIO;
                goto cleanup;
        }
@@ -221,7 +214,7 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
        xact = NULL;
 
        if (status != HN_NVS_STATUS_OK) {
-               if_printf(sc->hn_ifp, "rxbuf conn failed: %x\n", status);
+               if_printf(sc->hn_ifp, "nvs rxbuf conn failed: %x\n", status);
                error = EIO;
                goto cleanup;
        }
@@ -232,15 +225,12 @@ hv_nv_init_rx_buffer_with_net_vsp(struct
 cleanup:
        if (xact != NULL)
                vmbus_xact_put(xact);
-       hv_nv_destroy_rx_buffer(sc);
+       hn_nvs_disconn_rxbuf(sc);
        return (error);
 }
 
-/*
- * Net VSC initialize send buffer with net VSP
- */
 static int 
-hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
+hn_nvs_conn_chim(struct hn_softc *sc)
 {
        struct vmbus_xact *xact = NULL;
        struct hn_nvs_chim_conn *chim;
@@ -260,8 +250,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
            sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE,
            &sc->hn_chim_gpadl);
        if (error) {
-               if_printf(sc->hn_ifp, "chimney sending buffer gpadl "
-                   "connect failed: %d\n", error);
+               if_printf(sc->hn_ifp, "chim gpadl conn failed: %d\n", error);
                goto cleanup;
        }
 
@@ -284,7 +273,7 @@ hv_nv_init_send_buffer_with_net_vsp(stru
        resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len,
            HN_NVS_TYPE_CHIM_CONNRESP);
        if (resp == NULL) {
-               if_printf(sc->hn_ifp, "exec chim conn failed\n");
+               if_printf(sc->hn_ifp, "exec nvs chim conn failed\n");
                error = EIO;
                goto cleanup;
        }
@@ -295,14 +284,14 @@ hv_nv_init_send_buffer_with_net_vsp(stru
        xact = NULL;
 
        if (status != HN_NVS_STATUS_OK) {
-               if_printf(sc->hn_ifp, "chim conn failed: %x\n", status);
+               if_printf(sc->hn_ifp, "nvs chim conn failed: %x\n", status);
                error = EIO;
                goto cleanup;
        }
        if (sectsz == 0) {
                if_printf(sc->hn_ifp, "zero chimney sending buffer "
                    "section size\n");
-               return 0;
+               return (0);
        }
 
        sc->hn_chim_szmax = sectsz;
@@ -326,22 +315,19 @@ hv_nv_init_send_buffer_with_net_vsp(stru
                if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
                    sc->hn_chim_szmax, sc->hn_chim_cnt);
        }
-       return 0;
+       return (0);
 
 cleanup:
        if (xact != NULL)
                vmbus_xact_put(xact);
-       hv_nv_destroy_send_buffer(sc);
+       hn_nvs_disconn_chim(sc);
        return (error);
 }
 
-/*
- * Net VSC destroy receive buffer
- */
 static int
-hv_nv_destroy_rx_buffer(struct hn_softc *sc)
+hn_nvs_disconn_rxbuf(struct hn_softc *sc)
 {
-       int ret = 0;
+       int error;
 
        if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
                struct hn_nvs_rxbuf_disconn disconn;
@@ -354,38 +340,35 @@ hv_nv_destroy_rx_buffer(struct hn_softc 
                disconn.nvs_sig = HN_NVS_RXBUF_SIG;
 
                /* NOTE: No response. */
-               ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
-               if (ret != 0) {
+               error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
+               if (error) {
                        if_printf(sc->hn_ifp,
-                           "send rxbuf disconn failed: %d\n", ret);
-                       return (ret);
+                           "send nvs rxbuf disconn failed: %d\n", error);
+                       return (error);
                }
                sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
        }
-               
+
        if (sc->hn_rxbuf_gpadl != 0) {
                /*
                 * Disconnect RXBUF from primary channel.
                 */
-               ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
+               error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
                    sc->hn_rxbuf_gpadl);
-               if (ret != 0) {
+               if (error) {
                        if_printf(sc->hn_ifp,
-                           "rxbuf disconn failed: %d\n", ret);
-                       return (ret);
+                           "rxbuf gpadl disconn failed: %d\n", error);
+                       return (error);
                }
                sc->hn_rxbuf_gpadl = 0;
        }
-       return (ret);
+       return (0);
 }
 
-/*
- * Net VSC destroy send buffer
- */
 static int
-hv_nv_destroy_send_buffer(struct hn_softc *sc)
+hn_nvs_disconn_chim(struct hn_softc *sc)
 {
-       int ret = 0;
+       int error;
 
        if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
                struct hn_nvs_chim_disconn disconn;
@@ -398,25 +381,25 @@ hv_nv_destroy_send_buffer(struct hn_soft
                disconn.nvs_sig = HN_NVS_CHIM_SIG;
 
                /* NOTE: No response. */
-               ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
-               if (ret != 0) {
+               error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
+               if (error) {
                        if_printf(sc->hn_ifp,
-                           "send chim disconn failed: %d\n", ret);
-                       return (ret);
+                           "send nvs chim disconn failed: %d\n", error);
+                       return (error);
                }
                sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
        }
-               
+
        if (sc->hn_chim_gpadl != 0) {
                /*
                 * Disconnect chimney sending buffer from primary channel.
                 */
-               ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
+               error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
                    sc->hn_chim_gpadl);
-               if (ret != 0) {
+               if (error) {
                        if_printf(sc->hn_ifp,
-                           "chim disconn failed: %d\n", ret);
-                       return (ret);
+                           "chim gpadl disconn failed: %d\n", error);
+                       return (error);
                }
                sc->hn_chim_gpadl = 0;
        }
@@ -425,8 +408,7 @@ hv_nv_destroy_send_buffer(struct hn_soft
                free(sc->hn_chim_bmap, M_NETVSC);
                sc->hn_chim_bmap = NULL;
        }
-
-       return (ret);
+       return (0);
 }
 
 static int
@@ -537,38 +519,48 @@ hn_nvs_init(struct hn_softc *sc)
        return (ENXIO);
 }
 
-static int
-hv_nv_connect_to_vsp(struct hn_softc *sc, int mtu)
+int
+hn_nvs_attach(struct hn_softc *sc, int mtu)
 {
-       int ret;
+       int error;
 
        /*
         * Initialize NVS.
         */
-       ret = hn_nvs_init(sc);
-       if (ret != 0)
-               return (ret);
+       error = hn_nvs_init(sc);
+       if (error)
+               return (error);
 
        if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
                /*
                 * Configure NDIS before initializing it.
                 */
-               ret = hn_nvs_conf_ndis(sc, mtu);
-               if (ret != 0)
-                       return (ret);
+               error = hn_nvs_conf_ndis(sc, mtu);
+               if (error)
+                       return (error);
        }
 
        /*
         * Initialize NDIS.
         */
-       ret = hn_nvs_init_ndis(sc);
-       if (ret != 0)
-               return (ret);
-
-       ret = hv_nv_init_rx_buffer_with_net_vsp(sc);
-       if (ret == 0)
-               ret = hv_nv_init_send_buffer_with_net_vsp(sc);
-       return (ret);
+       error = hn_nvs_init_ndis(sc);
+       if (error)
+               return (error);
+
+       /*
+        * Connect RXBUF.
+        */
+       error = hn_nvs_conn_rxbuf(sc);
+       if (error)
+               return (error);
+
+       /*
+        * Connect chimney sending buffer.
+        */
+       error = hn_nvs_conn_chim(sc);
+       if (error)
+               return (error);
+       return (0);
 }
 
 /*
@@ -577,23 +569,8 @@ hv_nv_connect_to_vsp(struct hn_softc *sc
 static void
 hv_nv_disconnect_from_vsp(struct hn_softc *sc)
 {
-       hv_nv_destroy_rx_buffer(sc);
-       hv_nv_destroy_send_buffer(sc);
-}
-
-/*
- * Net VSC on device add
- * 
- * Callback when the device belonging to this driver is added
- */
-int
-hv_nv_on_device_add(struct hn_softc *sc, int mtu)
-{
-
-       /*
-        * Connect with the NetVsp
-        */
-       return (hv_nv_connect_to_vsp(sc, mtu));
+       hn_nvs_disconn_rxbuf(sc);
+       hn_nvs_disconn_chim(sc);
 }
 
 /*
@@ -604,11 +581,6 @@ hv_nv_on_device_remove(struct hn_softc *
 {
        
        hv_nv_disconnect_from_vsp(sc);
-
-       /* Now, we can close the channel safely */
-
-       vmbus_chan_close(sc->hn_prichan);
-
        return (0);
 }
 
@@ -675,3 +647,54 @@ hv_nv_on_send(struct vmbus_channel *chan
 
        return (ret);
 }
+
+int
+hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0)
+{
+       struct vmbus_xact *xact;
+       struct hn_nvs_subch_req *req;
+       const struct hn_nvs_subch_resp *resp;
+       int error, nsubch_req;
+       uint32_t nsubch;
+       size_t resp_len;
+
+       nsubch_req = *nsubch0;
+       KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req));
+
+       xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
+       if (xact == NULL) {
+               if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n");
+               return (ENXIO);
+       }
+       req = vmbus_xact_req_data(xact);
+       req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
+       req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
+       req->nvs_nsubch = nsubch_req;
+
+       resp_len = sizeof(*resp);
+       resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
+           HN_NVS_TYPE_SUBCH_RESP);
+       if (resp == NULL) {
+               if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n");
+               error = EIO;
+               goto done;
+       }
+       if (resp->nvs_status != HN_NVS_STATUS_OK) {
+               if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n",
+                   resp->nvs_status);
+               error = EIO;
+               goto done;
+       }
+
+       nsubch = resp->nvs_nsubch;
+       if (nsubch > nsubch_req) {
+               if_printf(sc->hn_ifp, "%u subchans are allocated, "
+                   "requested %d\n", nsubch, nsubch_req);
+               nsubch = nsubch_req;
+       }
+       *nsubch0 = nsubch;
+       error = 0;
+done:
+       vmbus_xact_put(xact);
+       return (error);
+}

Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h        Thu Oct 13 08:35:08 
2016        (r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h        Thu Oct 13 08:47:51 
2016        (r307206)
@@ -99,11 +99,6 @@ struct vmbus_channel;
 #define NETVSC_DEVICE_RING_BUFFER_SIZE (128 * PAGE_SIZE)
 #define NETVSC_PACKET_MAXPAGE          32
 
-typedef struct {
-       uint8_t         mac_addr[ETHER_ADDR_LEN];
-       uint32_t        link_state;
-} netvsc_device_info;
-
 #define HN_XACT_REQ_PGCNT              2
 #define HN_XACT_RESP_PGCNT             2
 #define HN_XACT_REQ_SIZE               (HN_XACT_REQ_PGCNT * PAGE_SIZE)
@@ -262,7 +257,7 @@ extern int hv_promisc_mode;
 struct hn_send_ctx;
 
 void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status);
-int hv_nv_on_device_add(struct hn_softc *sc, int mtu);
+int hn_nvs_attach(struct hn_softc *sc, int mtu);
 int hv_nv_on_device_remove(struct hn_softc *sc);
 int hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype,
        struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt);

Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Thu Oct 13 
08:35:08 2016        (r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c     Thu Oct 13 
08:47:51 2016        (r307206)
@@ -349,8 +349,12 @@ static int hn_create_rx_data(struct hn_s
 static void hn_destroy_rx_data(struct hn_softc *sc);
 static void hn_set_chim_size(struct hn_softc *, 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 *);
+static void hn_detach_allchans(struct hn_softc *);
 static void hn_chan_callback(struct vmbus_channel *chan, void *xrxr);
+static void hn_set_ring_inuse(struct hn_softc *, int);
+static int hn_synth_attach(struct hn_softc *, int);
 
 static void hn_nvs_handle_notify(struct hn_softc *sc,
                const struct vmbus_chanpkt_hdr *pkt);
@@ -368,6 +372,14 @@ static void hn_xmit_txeof(struct hn_tx_r
 static void hn_xmit_taskfunc(void *, int);
 static void hn_xmit_txeof_taskfunc(void *, int);
 
+static const uint8_t   hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
+       0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+       0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
+       0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
+       0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
+       0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
+};
+
 #if __FreeBSD_version >= 1100099
 static void
 hn_set_lro_lenlim(struct hn_softc *sc, int lenlim)
@@ -457,7 +469,8 @@ netvsc_attach(device_t dev)
 {
        struct sysctl_oid_list *child;
        struct sysctl_ctx_list *ctx;
-       netvsc_device_info device_info;
+       uint8_t eaddr[ETHER_ADDR_LEN];
+       uint32_t link_status;
        hn_softc_t *sc;
        int unit = device_get_unit(dev);
        struct ifnet *ifp = NULL;
@@ -535,9 +548,17 @@ netvsc_attach(device_t dev)
                goto failed;
 
        /*
-        * Associate the first TX/RX ring w/ the primary channel.
+        * Create transaction context for NVS and RNDIS transactions.
         */
-       error = hn_chan_attach(sc, sc->hn_prichan);
+       sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
+           HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
+       if (sc->hn_xact == NULL)
+               goto failed;
+
+       /*
+        * Attach the synthetic parts, i.e. NVS and RNDIS.
+        */
+       error = hn_synth_attach(sc, ETHERMTU);
        if (error)
                goto failed;
 
@@ -575,34 +596,6 @@ netvsc_attach(device_t dev)
            IFCAP_LRO;
        ifp->if_hwassist = sc->hn_tx_ring[0].hn_csum_assist | CSUM_TSO;
 
-       sc->hn_xact = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
-           HN_XACT_REQ_SIZE, HN_XACT_RESP_SIZE, 0);
-       if (sc->hn_xact == NULL)
-               goto failed;
-
-       error = hv_rf_on_device_add(sc, &device_info, &ring_cnt, ETHERMTU);
-       if (error)
-               goto failed;
-       KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_inuse,
-           ("invalid channel count %d, should be less than %d",
-            ring_cnt, sc->hn_rx_ring_inuse));
-
-       /*
-        * Set the # of TX/RX rings that could be used according to
-        * the # of channels that host offered.
-        */
-       if (sc->hn_tx_ring_inuse > ring_cnt)
-               sc->hn_tx_ring_inuse = ring_cnt;
-       sc->hn_rx_ring_inuse = ring_cnt;
-       device_printf(dev, "%d TX ring, %d RX ring\n",
-           sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
-
-       if (sc->hn_rx_ring_inuse > 1) {
-               error = hn_attach_subchans(sc);
-               if (error)
-                       goto failed;
-       }
-
 #if __FreeBSD_version >= 1100099
        if (sc->hn_rx_ring_inuse > 1) {
                /*
@@ -613,9 +606,11 @@ netvsc_attach(device_t dev)
        }
 #endif
 
-       if (device_info.link_state == NDIS_MEDIA_STATE_CONNECTED) {
+       error = hn_rndis_get_linkstatus(sc, &link_status);
+       if (error)
+               goto failed;
+       if (link_status == NDIS_MEDIA_STATE_CONNECTED)
                sc->hn_carrier = 1;
-       }
 
        tso_maxlen = hn_tso_maxlen;
        if (tso_maxlen <= 0 || tso_maxlen > IP_MAXPACKET)
@@ -626,7 +621,10 @@ netvsc_attach(device_t dev)
        ifp->if_hw_tsomax = tso_maxlen -
            (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
 
-       ether_ifattach(ifp, device_info.mac_addr);
+       error = hn_rndis_get_eaddr(sc, eaddr);
+       if (error)
+               goto failed;
+       ether_ifattach(ifp, eaddr);
 
        if_printf(ifp, "TSO: %u/%u/%u\n", ifp->if_hw_tsomax,
            ifp->if_hw_tsomaxsegcount, ifp->if_hw_tsomaxsegsize);
@@ -675,6 +673,7 @@ netvsc_detach(device_t dev)
         */
 
        hv_rf_on_device_remove(sc);
+       hn_detach_allchans(sc);
 
        hn_stop_tx_tasks(sc);
 
@@ -1519,8 +1518,7 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
 #ifdef INET
        struct ifaddr *ifa = (struct ifaddr *)data;
 #endif
-       netvsc_device_info device_info;
-       int mask, error = 0, ring_cnt;
+       int mask, error = 0;
        int retry_cnt = 500;
        
        switch(cmd) {
@@ -1591,43 +1589,16 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, 
                        break;
                }
 
-               /* Wait for subchannels to be destroyed */
-               vmbus_subchan_drain(sc->hn_prichan);
-
-               sc->hn_rx_ring[0].hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
-               sc->hn_tx_ring[0].hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
-               hn_chan_attach(sc, sc->hn_prichan); /* XXX check error */
-
-               ring_cnt = sc->hn_rx_ring_inuse;
-               error = hv_rf_on_device_add(sc, &device_info, &ring_cnt,
-                   ifr->ifr_mtu);
-               if (error) {
-                       NV_LOCK(sc);
-                       sc->temp_unusable = FALSE;
-                       NV_UNLOCK(sc);
-                       break;
-               }
-               /* # of channels can _not_ be changed */
-               KASSERT(sc->hn_rx_ring_inuse == ring_cnt,
-                   ("RX ring count %d and channel count %u mismatch",
-                    sc->hn_rx_ring_cnt, ring_cnt));
-               if (sc->hn_rx_ring_inuse > 1) {
-                       int r;
+               /*
+                * Detach all of the channels.
+                */
+               hn_detach_allchans(sc);
 
-                       /*
-                        * Skip the rings on primary channel; they are
-                        * handled by the hv_rf_on_device_add() above.
-                        */
-                       for (r = 1; r < sc->hn_rx_ring_cnt; ++r) {
-                               sc->hn_rx_ring[r].hn_rx_flags &=
-                                   ~HN_RX_FLAG_ATTACHED;
-                       }
-                       for (r = 1; r < sc->hn_tx_ring_cnt; ++r) {
-                               sc->hn_tx_ring[r].hn_tx_flags &=
-                                   ~HN_TX_FLAG_ATTACHED;
-                       }
-                       hn_attach_subchans(sc); /* XXX check error */
-               }
+               /*
+                * Attach the synthetic parts, i.e. NVS and RNDIS.
+                * XXX check error.
+                */
+               hn_synth_attach(sc, ifr->ifr_mtu);
 
                if (sc->hn_tx_ring[0].hn_chim_size > sc->hn_chim_szmax)
                        hn_set_chim_size(sc, sc->hn_chim_szmax);
@@ -3073,6 +3044,42 @@ hn_chan_attach(struct hn_softc *sc, stru
        return (error);
 }
 
+static void
+hn_chan_detach(struct hn_softc *sc, struct vmbus_channel *chan)
+{
+       struct hn_rx_ring *rxr;
+       int idx;
+
+       idx = vmbus_chan_subidx(chan);
+
+       /*
+        * Link this channel to RX/TX ring.
+        */
+       KASSERT(idx >= 0 && idx < sc->hn_rx_ring_inuse,
+           ("invalid channel index %d, should > 0 && < %d",
+            idx, sc->hn_rx_ring_inuse));
+       rxr = &sc->hn_rx_ring[idx];
+       KASSERT((rxr->hn_rx_flags & HN_RX_FLAG_ATTACHED),
+           ("RX ring %d is not attached", idx));
+       rxr->hn_rx_flags &= ~HN_RX_FLAG_ATTACHED;
+
+       if (idx < sc->hn_tx_ring_inuse) {
+               struct hn_tx_ring *txr = &sc->hn_tx_ring[idx];
+
+               KASSERT((txr->hn_tx_flags & HN_TX_FLAG_ATTACHED),
+                   ("TX ring %d is not attached attached", idx));
+               txr->hn_tx_flags &= ~HN_TX_FLAG_ATTACHED;
+       }
+
+       /*
+        * Close this channel.
+        *
+        * NOTE:
+        * Channel closing does _not_ destroy the target channel.
+        */
+       vmbus_chan_close(chan);
+}
+
 static int
 hn_attach_subchans(struct hn_softc *sc)
 {
@@ -3080,17 +3087,16 @@ hn_attach_subchans(struct hn_softc *sc)
        int subchan_cnt = sc->hn_rx_ring_inuse - 1;
        int i, error = 0;
 
-       /* Wait for sub-channels setup to complete. */
-       subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
+       if (subchan_cnt == 0)
+               return (0);
 
        /* Attach the sub-channels. */
+       subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
        for (i = 0; i < subchan_cnt; ++i) {
                error = hn_chan_attach(sc, subchans[i]);
                if (error)
                        break;
        }
-
-       /* Release the sub-channels */
        vmbus_subchan_rel(subchans, subchan_cnt);
 
        if (error) {
@@ -3105,6 +3111,202 @@ hn_attach_subchans(struct hn_softc *sc)
 }
 
 static void
+hn_detach_allchans(struct hn_softc *sc)
+{
+       struct vmbus_channel **subchans;
+       int subchan_cnt = sc->hn_rx_ring_inuse - 1;
+       int i;
+
+       if (subchan_cnt == 0)
+               goto back;
+
+       /* Detach the sub-channels. */
+       subchans = vmbus_subchan_get(sc->hn_prichan, subchan_cnt);
+       for (i = 0; i < subchan_cnt; ++i)
+               hn_chan_detach(sc, subchans[i]);
+       vmbus_subchan_rel(subchans, subchan_cnt);
+
+back:
+       /*
+        * Detach the primary channel, _after_ all sub-channels
+        * are detached.
+        */
+       hn_chan_detach(sc, sc->hn_prichan);
+
+       /* Wait for sub-channels to be destroyed, if any. */
+       vmbus_subchan_drain(sc->hn_prichan);
+
+#ifdef INVARIANTS
+       for (i = 0; i < sc->hn_rx_ring_cnt; ++i) {
+               KASSERT((sc->hn_rx_ring[i].hn_rx_flags &
+                   HN_RX_FLAG_ATTACHED) == 0,
+                   ("%dth RX ring is still attached", i));
+       }
+       for (i = 0; i < sc->hn_tx_ring_cnt; ++i) {
+               KASSERT((sc->hn_tx_ring[i].hn_tx_flags &
+                   HN_TX_FLAG_ATTACHED) == 0,
+                   ("%dth TX ring is still attached", i));
+       }
+#endif
+}
+
+static int
+hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch)
+{
+       struct vmbus_channel **subchans;
+       int nchan, rxr_cnt, error;
+
+       nchan = *nsubch + 1;
+       if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) {
+               /*
+                * Either RSS is not supported, or multiple RX/TX rings
+                * are not requested.
+                */
+               *nsubch = 0;
+               return (0);
+       }
+
+       /*
+        * Get RSS capabilities, e.g. # of RX rings, and # of indirect
+        * table entries.
+        */
+       error = hn_rndis_get_rsscaps(sc, &rxr_cnt);
+       if (error) {
+               /* No RSS; this is benign. */
+               *nsubch = 0;
+               return (0);
+       }
+       if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
+           rxr_cnt, nchan);
+
+       if (nchan > rxr_cnt)
+               nchan = rxr_cnt;
+       if (nchan == 1) {
+               if_printf(sc->hn_ifp, "only 1 channel is supported, no vRSS\n");
+               *nsubch = 0;
+               return (0);
+       }
+       
+       /*
+        * Allocate sub-channels from NVS.
+        */
+       *nsubch = nchan - 1;
+       error = hn_nvs_alloc_subchans(sc, nsubch);
+       if (error || *nsubch == 0) {
+               /* Failed to allocate sub-channels. */
+               *nsubch = 0;
+               return (0);
+       }
+
+       /*
+        * Wait for all sub-channels to become ready before moving on.
+        */
+       subchans = vmbus_subchan_get(sc->hn_prichan, *nsubch);
+       vmbus_subchan_rel(subchans, *nsubch);
+       return (0);
+}
+
+static int
+hn_synth_attach(struct hn_softc *sc, int mtu)
+{
+       struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
+       int error, nsubch, nchan, i;
+
+       /*
+        * Attach the primary channel _before_ attaching NVS and RNDIS.
+        */
+       error = hn_chan_attach(sc, sc->hn_prichan);
+       if (error)
+               return (error);
+
+       /*
+        * Attach NVS.
+        */
+       error = hn_nvs_attach(sc, mtu);
+       if (error)
+               return (error);
+
+       /*
+        * Attach RNDIS _after_ NVS is attached.
+        */
+       error = hn_rndis_attach(sc);
+       if (error)
+               return (error);
+
+       /*
+        * Allocate sub-channels for multi-TX/RX rings.
+        *
+        * NOTE:
+        * The # of RX rings that can be used is equivalent to the # of
+        * channels to be requested.
+        */
+       nsubch = sc->hn_rx_ring_cnt - 1;
+       error = hn_synth_alloc_subchans(sc, &nsubch);
+       if (error)
+               return (error);
+
+       nchan = nsubch + 1;
+       if (nchan == 1) {
+               /* Only the primary channel can be used; done */
+               goto back;
+       }
+
+       /*
+        * Configure RSS key and indirect table _after_ all sub-channels
+        * are allocated.
+        */
+
+       /* 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;
+
+       error = hn_rndis_conf_rss(sc);
+       if (error) {
+               /*
+                * Failed to configure RSS key or indirect table; only
+                * the primary channel can be used.
+                */
+               nchan = 1;
+       }
+back:
+       /*
+        * Set the # of TX/RX rings that could be used according to
+        * the # of channels that NVS offered.
+        */
+       hn_set_ring_inuse(sc, nchan);
+
+       /*
+        * Attach the sub-channels, if any.
+        */
+       error = hn_attach_subchans(sc);
+       if (error)
+               return (error);
+       return (0);
+}
+
+static void
+hn_set_ring_inuse(struct hn_softc *sc, int ring_cnt)
+{
+       KASSERT(ring_cnt > 0 && ring_cnt <= sc->hn_rx_ring_cnt,
+           ("invalid ring count %d", ring_cnt));
+
+       if (sc->hn_tx_ring_cnt > ring_cnt)
+               sc->hn_tx_ring_inuse = ring_cnt;
+       else
+               sc->hn_tx_ring_inuse = sc->hn_tx_ring_cnt;
+       sc->hn_rx_ring_inuse = ring_cnt;
+
+       if (bootverbose) {
+               if_printf(sc->hn_ifp, "%d TX ring, %d RX ring\n",
+                   sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
+       }
+}
+
+static void
 hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
 {
        const struct hn_nvs_hdr *hdr;

Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c   Thu Oct 13 08:35:08 
2016        (r307205)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c   Thu Oct 13 08:47:51 
2016        (r307206)
@@ -76,18 +76,12 @@ static void hv_rf_receive_indicate_statu
     const void *data, int dlen);
 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
     const void *data, int dlen);
-static int hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr);
-static int hv_rf_query_device_link_status(struct hn_softc *sc,
-    uint32_t *link_status);
-static int  hv_rf_init_device(struct hn_softc *sc);
 
 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_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_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
-static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
 
 static __inline uint32_t
 hn_rndis_rid(struct hn_softc *sc)
@@ -481,11 +475,8 @@ hv_rf_on_receive(struct hn_softc *sc, st
        }
 }
 
-/*
- * RNDIS filter query device MAC address
- */
-static int
-hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr)
+int
+hn_rndis_get_eaddr(struct hn_softc *sc, uint8_t *eaddr)
 {
        size_t eaddr_len;
        int error;
@@ -502,11 +493,8 @@ hv_rf_query_device_mac(struct hn_softc *
        return (0);
 }
 
-/*
- * RNDIS filter query device link status
- */
-static int
-hv_rf_query_device_link_status(struct hn_softc *sc, uint32_t *link_status)
+int
+hn_rndis_get_linkstatus(struct hn_softc *sc, uint32_t *link_status)
 {
        size_t size;
        int error;
@@ -523,14 +511,6 @@ hv_rf_query_device_link_status(struct hn
        return (0);
 }
 
-static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
-       0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
-       0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
-       0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
-       0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
-       0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
-};
-
 static const void *
 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t 
reqlen,
     struct hn_send_ctx *sndc, size_t *comp_len)
@@ -722,7 +702,7 @@ done:
        return (error);
 }
 
-static int
+int
 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
 {
        struct ndis_rss_caps in, caps;
@@ -857,12 +837,12 @@ hn_rndis_conf_offload(struct hn_softc *s
        return (error);
 }
 
-static int
-hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
+int
+hn_rndis_conf_rss(struct hn_softc *sc)
 {
        struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
        struct ndis_rss_params *prm = &rss->rss_params;
-       int i, error;
+       int error;
 
        /*
         * Only NDIS 6.30+ is supported.
@@ -870,7 +850,12 @@ hn_rndis_conf_rss(struct hn_softc *sc, i
        KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
            ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
 
-       memset(rss, 0, sizeof(*rss));
+       /*
+        * NOTE:
+        * DO NOT whack rss_key and rss_ind, which are setup by the caller.
+        */
+       memset(prm, 0, sizeof(*prm));
+
        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);
@@ -885,14 +870,6 @@ hn_rndis_conf_rss(struct hn_softc *sc, i
        prm->ndis_keyoffset =
            __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
 
-       /* Setup RSS key */
-       memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
-
-       /* Setup RSS indirect table */
-       /* TODO: Take ndis_rss_caps.ndis_nind into account */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to