The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/hyperv/netvsc/hn_nvs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2009-2012,2016-2017 Microsoft Corp.
    3  * Copyright (c) 2010-2012 Citrix Inc.
    4  * Copyright (c) 2012 NetApp Inc.
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice unmodified, this list of conditions, and the following
   12  *    disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /*
   30  * Network Virtualization Service.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "opt_inet6.h"
   37 #include "opt_inet.h"
   38 
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/limits.h>
   42 #include <sys/socket.h>
   43 #include <sys/systm.h>
   44 #include <sys/taskqueue.h>
   45 
   46 #include <net/ethernet.h>
   47 #include <net/if.h>
   48 #include <net/if_var.h>
   49 #include <net/if_media.h>
   50 
   51 #include <netinet/in.h>
   52 #include <netinet/tcp_lro.h>
   53 
   54 #include <dev/hyperv/include/hyperv.h>
   55 #include <dev/hyperv/include/hyperv_busdma.h>
   56 #include <dev/hyperv/include/vmbus.h>
   57 #include <dev/hyperv/include/vmbus_xact.h>
   58 
   59 #include <dev/hyperv/netvsc/ndis.h>
   60 #include <dev/hyperv/netvsc/if_hnreg.h>
   61 #include <dev/hyperv/netvsc/if_hnvar.h>
   62 #include <dev/hyperv/netvsc/hn_nvs.h>
   63 
   64 static int                      hn_nvs_conn_chim(struct hn_softc *);
   65 static int                      hn_nvs_conn_rxbuf(struct hn_softc *);
   66 static void                     hn_nvs_disconn_chim(struct hn_softc *);
   67 static void                     hn_nvs_disconn_rxbuf(struct hn_softc *);
   68 static int                      hn_nvs_conf_ndis(struct hn_softc *, int);
   69 static int                      hn_nvs_init_ndis(struct hn_softc *);
   70 static int                      hn_nvs_doinit(struct hn_softc *, uint32_t);
   71 static int                      hn_nvs_init(struct hn_softc *);
   72 static const void               *hn_nvs_xact_execute(struct hn_softc *,
   73                                     struct vmbus_xact *, void *, int,
   74                                     size_t *, uint32_t);
   75 static void                     hn_nvs_sent_none(struct hn_nvs_sendctx *,
   76                                     struct hn_softc *, struct vmbus_channel *,
   77                                     const void *, int);
   78 
   79 struct hn_nvs_sendctx           hn_nvs_sendctx_none =
   80     HN_NVS_SENDCTX_INITIALIZER(hn_nvs_sent_none, NULL);
   81 
   82 static const uint32_t           hn_nvs_version[] = {
   83         HN_NVS_VERSION_61,
   84         HN_NVS_VERSION_6,
   85         HN_NVS_VERSION_5,
   86         HN_NVS_VERSION_4,
   87         HN_NVS_VERSION_2,
   88         HN_NVS_VERSION_1
   89 };
   90 
   91 static const void *
   92 hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact,
   93     void *req, int reqlen, size_t *resplen0, uint32_t type)
   94 {
   95         struct hn_nvs_sendctx sndc;
   96         size_t resplen, min_resplen = *resplen0;
   97         const struct hn_nvs_hdr *hdr;
   98         int error;
   99 
  100         KASSERT(min_resplen >= sizeof(*hdr),
  101             ("invalid minimum response len %zu", min_resplen));
  102 
  103         /*
  104          * Execute the xact setup by the caller.
  105          */
  106         hn_nvs_sendctx_init(&sndc, hn_nvs_sent_xact, xact);
  107 
  108         vmbus_xact_activate(xact);
  109         error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC,
  110             req, reqlen, &sndc);
  111         if (error) {
  112                 vmbus_xact_deactivate(xact);
  113                 return (NULL);
  114         }
  115         hdr = vmbus_chan_xact_wait(sc->hn_prichan, xact, &resplen,
  116             HN_CAN_SLEEP(sc));
  117 
  118         /*
  119          * Check this NVS response message.
  120          */
  121         if (resplen < min_resplen) {
  122                 if_printf(sc->hn_ifp, "invalid NVS resp len %zu\n", resplen);
  123                 return (NULL);
  124         }
  125         if (hdr->nvs_type != type) {
  126                 if_printf(sc->hn_ifp, "unexpected NVS resp 0x%08x, "
  127                     "expect 0x%08x\n", hdr->nvs_type, type);
  128                 return (NULL);
  129         }
  130         /* All pass! */
  131         *resplen0 = resplen;
  132         return (hdr);
  133 }
  134 
  135 static __inline int
  136 hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen)
  137 {
  138 
  139         return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE,
  140             req, reqlen, &hn_nvs_sendctx_none));
  141 }
  142 
  143 static int 
  144 hn_nvs_conn_rxbuf(struct hn_softc *sc)
  145 {
  146         struct vmbus_xact *xact = NULL;
  147         struct hn_nvs_rxbuf_conn *conn;
  148         const struct hn_nvs_rxbuf_connresp *resp;
  149         size_t resp_len;
  150         uint32_t status;
  151         int error, rxbuf_size;
  152 
  153         /*
  154          * Limit RXBUF size for old NVS.
  155          */
  156         if (sc->hn_nvs_ver <= HN_NVS_VERSION_2)
  157                 rxbuf_size = HN_RXBUF_SIZE_COMPAT;
  158         else
  159                 rxbuf_size = HN_RXBUF_SIZE;
  160 
  161         /*
  162          * Connect the RXBUF GPADL to the primary channel.
  163          *
  164          * NOTE:
  165          * Only primary channel has RXBUF connected to it.  Sub-channels
  166          * just share this RXBUF.
  167          */
  168         error = vmbus_chan_gpadl_connect(sc->hn_prichan,
  169             sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
  170         if (error) {
  171                 if_printf(sc->hn_ifp, "rxbuf gpadl conn failed: %d\n",
  172                     error);
  173                 goto cleanup;
  174         }
  175 
  176         /*
  177          * Connect RXBUF to NVS.
  178          */
  179 
  180         xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn));
  181         if (xact == NULL) {
  182                 if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n");
  183                 error = ENXIO;
  184                 goto cleanup;
  185         }
  186         conn = vmbus_xact_req_data(xact);
  187         conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN;
  188         conn->nvs_gpadl = sc->hn_rxbuf_gpadl;
  189         conn->nvs_sig = HN_NVS_RXBUF_SIG;
  190 
  191         resp_len = sizeof(*resp);
  192         resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len,
  193             HN_NVS_TYPE_RXBUF_CONNRESP);
  194         if (resp == NULL) {
  195                 if_printf(sc->hn_ifp, "exec nvs rxbuf conn failed\n");
  196                 error = EIO;
  197                 goto cleanup;
  198         }
  199 
  200         status = resp->nvs_status;
  201         vmbus_xact_put(xact);
  202         xact = NULL;
  203 
  204         if (status != HN_NVS_STATUS_OK) {
  205                 if_printf(sc->hn_ifp, "nvs rxbuf conn failed: %x\n", status);
  206                 error = EIO;
  207                 goto cleanup;
  208         }
  209         sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED;
  210 
  211         return (0);
  212 
  213 cleanup:
  214         if (xact != NULL)
  215                 vmbus_xact_put(xact);
  216         hn_nvs_disconn_rxbuf(sc);
  217         return (error);
  218 }
  219 
  220 static int 
  221 hn_nvs_conn_chim(struct hn_softc *sc)
  222 {
  223         struct vmbus_xact *xact = NULL;
  224         struct hn_nvs_chim_conn *chim;
  225         const struct hn_nvs_chim_connresp *resp;
  226         size_t resp_len;
  227         uint32_t status, sectsz;
  228         int error;
  229 
  230         /*
  231          * Connect chimney sending buffer GPADL to the primary channel.
  232          *
  233          * NOTE:
  234          * Only primary channel has chimney sending buffer connected to it.
  235          * Sub-channels just share this chimney sending buffer.
  236          */
  237         error = vmbus_chan_gpadl_connect(sc->hn_prichan,
  238             sc->hn_chim_dma.hv_paddr, HN_CHIM_SIZE, &sc->hn_chim_gpadl);
  239         if (error) {
  240                 if_printf(sc->hn_ifp, "chim gpadl conn failed: %d\n", error);
  241                 goto cleanup;
  242         }
  243 
  244         /*
  245          * Connect chimney sending buffer to NVS
  246          */
  247 
  248         xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim));
  249         if (xact == NULL) {
  250                 if_printf(sc->hn_ifp, "no xact for nvs chim conn\n");
  251                 error = ENXIO;
  252                 goto cleanup;
  253         }
  254         chim = vmbus_xact_req_data(xact);
  255         chim->nvs_type = HN_NVS_TYPE_CHIM_CONN;
  256         chim->nvs_gpadl = sc->hn_chim_gpadl;
  257         chim->nvs_sig = HN_NVS_CHIM_SIG;
  258 
  259         resp_len = sizeof(*resp);
  260         resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len,
  261             HN_NVS_TYPE_CHIM_CONNRESP);
  262         if (resp == NULL) {
  263                 if_printf(sc->hn_ifp, "exec nvs chim conn failed\n");
  264                 error = EIO;
  265                 goto cleanup;
  266         }
  267 
  268         status = resp->nvs_status;
  269         sectsz = resp->nvs_sectsz;
  270         vmbus_xact_put(xact);
  271         xact = NULL;
  272 
  273         if (status != HN_NVS_STATUS_OK) {
  274                 if_printf(sc->hn_ifp, "nvs chim conn failed: %x\n", status);
  275                 error = EIO;
  276                 goto cleanup;
  277         }
  278         if (sectsz == 0 || sectsz % sizeof(uint32_t) != 0) {
  279                 /*
  280                  * Can't use chimney sending buffer; done!
  281                  */
  282                 if (sectsz == 0) {
  283                         if_printf(sc->hn_ifp, "zero chimney sending buffer "
  284                             "section size\n");
  285                 } else {
  286                         if_printf(sc->hn_ifp, "misaligned chimney sending "
  287                             "buffers, section size: %u\n", sectsz);
  288                 }
  289                 sc->hn_chim_szmax = 0;
  290                 sc->hn_chim_cnt = 0;
  291                 sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
  292                 return (0);
  293         }
  294 
  295         sc->hn_chim_szmax = sectsz;
  296         sc->hn_chim_cnt = HN_CHIM_SIZE / sc->hn_chim_szmax;
  297         if (HN_CHIM_SIZE % sc->hn_chim_szmax != 0) {
  298                 if_printf(sc->hn_ifp, "chimney sending sections are "
  299                     "not properly aligned\n");
  300         }
  301         if (sc->hn_chim_cnt % LONG_BIT != 0) {
  302                 if_printf(sc->hn_ifp, "discard %d chimney sending sections\n",
  303                     sc->hn_chim_cnt % LONG_BIT);
  304         }
  305 
  306         sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT;
  307         sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long),
  308             M_DEVBUF, M_WAITOK | M_ZERO);
  309 
  310         /* Done! */
  311         sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
  312         if (bootverbose) {
  313                 if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
  314                     sc->hn_chim_szmax, sc->hn_chim_cnt);
  315         }
  316         return (0);
  317 
  318 cleanup:
  319         if (xact != NULL)
  320                 vmbus_xact_put(xact);
  321         hn_nvs_disconn_chim(sc);
  322         return (error);
  323 }
  324 
  325 static void
  326 hn_nvs_disconn_rxbuf(struct hn_softc *sc)
  327 {
  328         int error;
  329 
  330         if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
  331                 struct hn_nvs_rxbuf_disconn disconn;
  332 
  333                 /*
  334                  * Disconnect RXBUF from NVS.
  335                  */
  336                 memset(&disconn, 0, sizeof(disconn));
  337                 disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN;
  338                 disconn.nvs_sig = HN_NVS_RXBUF_SIG;
  339 
  340                 /* NOTE: No response. */
  341                 error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
  342                 if (error) {
  343                         if_printf(sc->hn_ifp,
  344                             "send nvs rxbuf disconn failed: %d\n", error);
  345                         /*
  346                          * Fine for a revoked channel, since the hypervisor
  347                          * does not drain TX bufring for a revoked channel.
  348                          */
  349                         if (!vmbus_chan_is_revoked(sc->hn_prichan))
  350                                 sc->hn_flags |= HN_FLAG_RXBUF_REF;
  351                 }
  352                 sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
  353 
  354                 /*
  355                  * Wait for the hypervisor to receive this NVS request.
  356                  *
  357                  * NOTE:
  358                  * The TX bufring will not be drained by the hypervisor,
  359                  * if the primary channel is revoked.
  360                  */
  361                 while (!vmbus_chan_tx_empty(sc->hn_prichan) &&
  362                     !vmbus_chan_is_revoked(sc->hn_prichan))
  363                         pause("waittx", 1);
  364                 /*
  365                  * Linger long enough for NVS to disconnect RXBUF.
  366                  */
  367                 pause("lingtx", (200 * hz) / 1000);
  368         }
  369 
  370         if (vmbus_current_version < VMBUS_VERSION_WIN10 && sc->hn_rxbuf_gpadl != 0) {
  371                 /*
  372                  * Disconnect RXBUF from primary channel.
  373                  */
  374                 error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
  375                     sc->hn_rxbuf_gpadl);
  376                 if (error) {
  377                         if_printf(sc->hn_ifp,
  378                             "rxbuf gpadl disconn failed: %d\n", error);
  379                         sc->hn_flags |= HN_FLAG_RXBUF_REF;
  380                 }
  381                 sc->hn_rxbuf_gpadl = 0;
  382         }
  383 }
  384 
  385 static void
  386 hn_nvs_disconn_chim(struct hn_softc *sc)
  387 {
  388         int error;
  389 
  390         if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
  391                 struct hn_nvs_chim_disconn disconn;
  392 
  393                 /*
  394                  * Disconnect chimney sending buffer from NVS.
  395                  */
  396                 memset(&disconn, 0, sizeof(disconn));
  397                 disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN;
  398                 disconn.nvs_sig = HN_NVS_CHIM_SIG;
  399 
  400                 /* NOTE: No response. */
  401                 error = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
  402                 if (error) {
  403                         if_printf(sc->hn_ifp,
  404                             "send nvs chim disconn failed: %d\n", error);
  405                         /*
  406                          * Fine for a revoked channel, since the hypervisor
  407                          * does not drain TX bufring for a revoked channel.
  408                          */
  409                         if (!vmbus_chan_is_revoked(sc->hn_prichan))
  410                                 sc->hn_flags |= HN_FLAG_CHIM_REF;
  411                 }
  412                 sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
  413 
  414                 /*
  415                  * Wait for the hypervisor to receive this NVS request.
  416                  *
  417                  * NOTE:
  418                  * The TX bufring will not be drained by the hypervisor,
  419                  * if the primary channel is revoked.
  420                  */
  421                 while (!vmbus_chan_tx_empty(sc->hn_prichan) &&
  422                     !vmbus_chan_is_revoked(sc->hn_prichan))
  423                         pause("waittx", 1);
  424                 /*
  425                  * Linger long enough for NVS to disconnect chimney
  426                  * sending buffer.
  427                  */
  428                 pause("lingtx", (200 * hz) / 1000);
  429         }
  430 
  431         if (vmbus_current_version < VMBUS_VERSION_WIN10 && sc->hn_chim_gpadl != 0) {
  432                 /*
  433                  * Disconnect chimney sending buffer from primary channel.
  434                  */
  435                 error = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
  436                     sc->hn_chim_gpadl);
  437                 if (error) {
  438                         if_printf(sc->hn_ifp,
  439                             "chim gpadl disconn failed: %d\n", error);
  440                         sc->hn_flags |= HN_FLAG_CHIM_REF;
  441                 }
  442                 sc->hn_chim_gpadl = 0;
  443         }
  444 
  445         if (sc->hn_chim_bmap != NULL) {
  446                 free(sc->hn_chim_bmap, M_DEVBUF);
  447                 sc->hn_chim_bmap = NULL;
  448                 sc->hn_chim_bmap_cnt = 0;
  449         }
  450 }
  451 
  452 static int
  453 hn_nvs_doinit(struct hn_softc *sc, uint32_t nvs_ver)
  454 {
  455         struct vmbus_xact *xact;
  456         struct hn_nvs_init *init;
  457         const struct hn_nvs_init_resp *resp;
  458         size_t resp_len;
  459         uint32_t status;
  460 
  461         xact = vmbus_xact_get(sc->hn_xact, sizeof(*init));
  462         if (xact == NULL) {
  463                 if_printf(sc->hn_ifp, "no xact for nvs init\n");
  464                 return (ENXIO);
  465         }
  466         init = vmbus_xact_req_data(xact);
  467         init->nvs_type = HN_NVS_TYPE_INIT;
  468         init->nvs_ver_min = nvs_ver;
  469         init->nvs_ver_max = nvs_ver;
  470 
  471         resp_len = sizeof(*resp);
  472         resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len,
  473             HN_NVS_TYPE_INIT_RESP);
  474         if (resp == NULL) {
  475                 if_printf(sc->hn_ifp, "exec init failed\n");
  476                 vmbus_xact_put(xact);
  477                 return (EIO);
  478         }
  479 
  480         status = resp->nvs_status;
  481         vmbus_xact_put(xact);
  482 
  483         if (status != HN_NVS_STATUS_OK) {
  484                 if (bootverbose) {
  485                         /*
  486                          * Caller may try another NVS version, and will log
  487                          * error if there are no more NVS versions to try,
  488                          * so don't bark out loud here.
  489                          */
  490                         if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n",
  491                             nvs_ver);
  492                 }
  493                 return (EINVAL);
  494         }
  495         return (0);
  496 }
  497 
  498 /*
  499  * Configure MTU and enable VLAN.
  500  */
  501 static int
  502 hn_nvs_conf_ndis(struct hn_softc *sc, int mtu)
  503 {
  504         struct hn_nvs_ndis_conf conf;
  505         int error;
  506 
  507         memset(&conf, 0, sizeof(conf));
  508         conf.nvs_type = HN_NVS_TYPE_NDIS_CONF;
  509         conf.nvs_mtu = mtu + ETHER_HDR_LEN;
  510         conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN;
  511         if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
  512                 conf.nvs_caps |= HN_NVS_NDIS_CONF_SRIOV;
  513         if (sc->hn_nvs_ver >= HN_NVS_VERSION_61)
  514                 conf.nvs_caps |= HN_NVS_NDIS_CONF_RSC;
  515 
  516 
  517         /* NOTE: No response. */
  518         error = hn_nvs_req_send(sc, &conf, sizeof(conf));
  519         if (error) {
  520                 if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
  521                 return (error);
  522         }
  523 
  524         if (bootverbose)
  525                 if_printf(sc->hn_ifp, "nvs ndis conf done\n");
  526         sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN;
  527         return (0);
  528 }
  529 
  530 static int
  531 hn_nvs_init_ndis(struct hn_softc *sc)
  532 {
  533         struct hn_nvs_ndis_init ndis;
  534         int error;
  535 
  536         memset(&ndis, 0, sizeof(ndis));
  537         ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
  538         ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver);
  539         ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver);
  540 
  541         /* NOTE: No response. */
  542         error = hn_nvs_req_send(sc, &ndis, sizeof(ndis));
  543         if (error)
  544                 if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error);
  545         return (error);
  546 }
  547 
  548 static int
  549 hn_nvs_init(struct hn_softc *sc)
  550 {
  551         int i, error;
  552 
  553         if (device_is_attached(sc->hn_dev)) {
  554                 /*
  555                  * NVS version and NDIS version MUST NOT be changed.
  556                  */
  557                 if (bootverbose) {
  558                         if_printf(sc->hn_ifp, "reinit NVS version 0x%x, "
  559                             "NDIS version %u.%u\n", sc->hn_nvs_ver,
  560                             HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
  561                             HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
  562                 }
  563 
  564                 error = hn_nvs_doinit(sc, sc->hn_nvs_ver);
  565                 if (error) {
  566                         if_printf(sc->hn_ifp, "reinit NVS version 0x%x "
  567                             "failed: %d\n", sc->hn_nvs_ver, error);
  568                         return (error);
  569                 }
  570                 goto done;
  571         }
  572 
  573         /*
  574          * Find the supported NVS version and set NDIS version accordingly.
  575          */
  576         for (i = 0; i < nitems(hn_nvs_version); ++i) {
  577                 error = hn_nvs_doinit(sc, hn_nvs_version[i]);
  578                 if (!error) {
  579                         sc->hn_nvs_ver = hn_nvs_version[i];
  580 
  581                         /* Set NDIS version according to NVS version. */
  582                         sc->hn_ndis_ver = HN_NDIS_VERSION_6_30;
  583                         if (sc->hn_nvs_ver <= HN_NVS_VERSION_4)
  584                                 sc->hn_ndis_ver = HN_NDIS_VERSION_6_1;
  585 
  586                         if (bootverbose) {
  587                                 if_printf(sc->hn_ifp, "NVS version 0x%x, "
  588                                     "NDIS version %u.%u\n", sc->hn_nvs_ver,
  589                                     HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
  590                                     HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
  591                         }
  592                         goto done;
  593                 }
  594         }
  595         if_printf(sc->hn_ifp, "no NVS available\n");
  596         return (ENXIO);
  597 
  598 done:
  599         if (sc->hn_nvs_ver >= HN_NVS_VERSION_5)
  600                 sc->hn_caps |= HN_CAP_HASHVAL;
  601         return (0);
  602 }
  603 
  604 int
  605 hn_nvs_attach(struct hn_softc *sc, int mtu)
  606 {
  607         int error;
  608 
  609         if (hyperv_ver_major >= 10) {
  610                 /* UDP 4-tuple hash is enforced. */
  611                 sc->hn_caps |= HN_CAP_UDPHASH;
  612         }
  613 
  614         /*
  615          * Initialize NVS.
  616          */
  617         error = hn_nvs_init(sc);
  618         if (error)
  619                 return (error);
  620 
  621         if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
  622                 /*
  623                  * Configure NDIS before initializing it.
  624                  */
  625                 error = hn_nvs_conf_ndis(sc, mtu);
  626                 if (error)
  627                         return (error);
  628         }
  629 
  630         /*
  631          * Initialize NDIS.
  632          */
  633         error = hn_nvs_init_ndis(sc);
  634         if (error)
  635                 return (error);
  636 
  637         /*
  638          * Connect RXBUF.
  639          */
  640         error = hn_nvs_conn_rxbuf(sc);
  641         if (error)
  642                 return (error);
  643 
  644         /*
  645          * Connect chimney sending buffer.
  646          */
  647         error = hn_nvs_conn_chim(sc);
  648         if (error) {
  649                 hn_nvs_disconn_rxbuf(sc);
  650                 return (error);
  651         }
  652         return (0);
  653 }
  654 
  655 void
  656 hn_nvs_detach(struct hn_softc *sc)
  657 {
  658 
  659         /* NOTE: there are no requests to stop the NVS. */
  660         hn_nvs_disconn_rxbuf(sc);
  661         hn_nvs_disconn_chim(sc);
  662 }
  663 
  664 void
  665 hn_nvs_sent_xact(struct hn_nvs_sendctx *sndc,
  666     struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
  667     const void *data, int dlen)
  668 {
  669 
  670         vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen);
  671 }
  672 
  673 static void
  674 hn_nvs_sent_none(struct hn_nvs_sendctx *sndc __unused,
  675     struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
  676     const void *data __unused, int dlen __unused)
  677 {
  678         /* EMPTY */
  679 }
  680 
  681 int
  682 hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0)
  683 {
  684         struct vmbus_xact *xact;
  685         struct hn_nvs_subch_req *req;
  686         const struct hn_nvs_subch_resp *resp;
  687         int error, nsubch_req;
  688         uint32_t nsubch;
  689         size_t resp_len;
  690 
  691         nsubch_req = *nsubch0;
  692         KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req));
  693 
  694         xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
  695         if (xact == NULL) {
  696                 if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n");
  697                 return (ENXIO);
  698         }
  699         req = vmbus_xact_req_data(xact);
  700         req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
  701         req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
  702         req->nvs_nsubch = nsubch_req;
  703 
  704         resp_len = sizeof(*resp);
  705         resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
  706             HN_NVS_TYPE_SUBCH_RESP);
  707         if (resp == NULL) {
  708                 if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n");
  709                 error = EIO;
  710                 goto done;
  711         }
  712         if (resp->nvs_status != HN_NVS_STATUS_OK) {
  713                 if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n",
  714                     resp->nvs_status);
  715                 error = EIO;
  716                 goto done;
  717         }
  718 
  719         nsubch = resp->nvs_nsubch;
  720         if (nsubch > nsubch_req) {
  721                 if_printf(sc->hn_ifp, "%u subchans are allocated, "
  722                     "requested %d\n", nsubch, nsubch_req);
  723                 nsubch = nsubch_req;
  724         }
  725         *nsubch0 = nsubch;
  726         error = 0;
  727 done:
  728         vmbus_xact_put(xact);
  729         return (error);
  730 }
  731 
  732 int
  733 hn_nvs_send_rndis_ctrl(struct vmbus_channel *chan,
  734     struct hn_nvs_sendctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
  735 {
  736 
  737         return hn_nvs_send_rndis_sglist(chan, HN_NVS_RNDIS_MTYPE_CTRL,
  738             sndc, gpa, gpa_cnt);
  739 }
  740 
  741 void
  742 hn_nvs_set_datapath(struct hn_softc *sc, uint32_t path)
  743 {
  744         struct hn_nvs_datapath dp;
  745 
  746         memset(&dp, 0, sizeof(dp));
  747         dp.nvs_type = HN_NVS_TYPE_SET_DATAPATH;
  748         dp.nvs_active_path = path;
  749 
  750         hn_nvs_req_send(sc, &dp, sizeof(dp));
  751 }

Cache object: 2e2d96aab5990acc2fcc74566770fd1e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.