2 * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 * Copyright (c) 2010-2012 Citrix Inc.
4 * Copyright (c) 2012 NetApp Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
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.
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.
32 * HyperV vmbus network VSC (virtual services client) module
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/socket.h>
40 #include <sys/limits.h>
43 #include <net/if_var.h>
44 #include <net/if_arp.h>
45 #include <machine/bus.h>
46 #include <machine/atomic.h>
48 #include <dev/hyperv/include/hyperv.h>
49 #include <dev/hyperv/include/vmbus_xact.h>
50 #include <dev/hyperv/netvsc/hv_net_vsc.h>
51 #include <dev/hyperv/netvsc/hv_rndis_filter.h>
52 #include <dev/hyperv/netvsc/if_hnreg.h>
53 #include <dev/hyperv/netvsc/if_hnvar.h>
55 MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver");
58 * Forward declarations
60 static int hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc);
61 static int hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *);
62 static int hv_nv_destroy_send_buffer(struct hn_softc *sc);
63 static int hv_nv_destroy_rx_buffer(struct hn_softc *sc);
64 static int hv_nv_connect_to_vsp(struct hn_softc *sc, int mtu);
65 static void hn_nvs_sent_none(struct hn_send_ctx *sndc,
66 struct hn_softc *, struct vmbus_channel *chan,
69 struct hn_send_ctx hn_send_ctx_none =
70 HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL);
72 static const uint32_t hn_nvs_version[] = {
80 hn_chim_alloc(struct hn_softc *sc)
82 int i, bmap_cnt = sc->hn_chim_bmap_cnt;
83 u_long *bmap = sc->hn_chim_bmap;
84 uint32_t ret = HN_NVS_CHIM_IDX_INVALID;
86 for (i = 0; i < bmap_cnt; ++i) {
93 --idx; /* ffsl is 1-based */
94 KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt,
95 ("invalid i %d and idx %d", i, idx));
97 if (atomic_testandset_long(&bmap[i], idx))
100 ret = i * LONG_BIT + idx;
107 hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact,
108 void *req, int reqlen, size_t *resplen0, uint32_t type)
110 struct hn_send_ctx sndc;
111 size_t resplen, min_resplen = *resplen0;
112 const struct hn_nvs_hdr *hdr;
115 KASSERT(min_resplen >= sizeof(*hdr),
116 ("invalid minimum response len %zu", min_resplen));
119 * Execute the xact setup by the caller.
121 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
123 vmbus_xact_activate(xact);
124 error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC,
127 vmbus_xact_deactivate(xact);
130 hdr = vmbus_xact_wait(xact, &resplen);
133 * Check this NVS response message.
135 if (resplen < min_resplen) {
136 if_printf(sc->hn_ifp, "invalid NVS resp len %zu\n", resplen);
139 if (hdr->nvs_type != type) {
140 if_printf(sc->hn_ifp, "unexpected NVS resp 0x%08x, "
141 "expect 0x%08x\n", hdr->nvs_type, type);
150 hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen)
153 return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE,
154 req, reqlen, &hn_send_ctx_none));
158 * Net VSC initialize receive buffer with net VSP
160 * Net VSP: Network virtual services client, also known as the
161 * Hyper-V extensible switch and the synthetic data path.
164 hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc)
166 struct vmbus_xact *xact = NULL;
167 struct hn_nvs_rxbuf_conn *conn;
168 const struct hn_nvs_rxbuf_connresp *resp;
171 int error, rxbuf_size;
174 * Limit RXBUF size for old NVS.
176 if (sc->hn_nvs_ver <= HN_NVS_VERSION_2)
177 rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY;
179 rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE;
182 * Connect the RXBUF GPADL to the primary channel.
185 * Only primary channel has RXBUF connected to it. Sub-channels
186 * just share this RXBUF.
188 error = vmbus_chan_gpadl_connect(sc->hn_prichan,
189 sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl);
191 if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n",
197 * Connect RXBUF to NVS.
200 xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn));
202 if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n");
206 conn = vmbus_xact_req_data(xact);
207 conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN;
208 conn->nvs_gpadl = sc->hn_rxbuf_gpadl;
209 conn->nvs_sig = HN_NVS_RXBUF_SIG;
211 resp_len = sizeof(*resp);
212 resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len,
213 HN_NVS_TYPE_RXBUF_CONNRESP);
215 if_printf(sc->hn_ifp, "exec rxbuf conn failed\n");
220 status = resp->nvs_status;
221 vmbus_xact_put(xact);
224 if (status != HN_NVS_STATUS_OK) {
225 if_printf(sc->hn_ifp, "rxbuf conn failed: %x\n", status);
229 sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED;
235 vmbus_xact_put(xact);
236 hv_nv_destroy_rx_buffer(sc);
241 * Net VSC initialize send buffer with net VSP
244 hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc)
246 struct vmbus_xact *xact = NULL;
247 struct hn_nvs_chim_conn *chim;
248 const struct hn_nvs_chim_connresp *resp;
250 uint32_t status, sectsz;
254 * Connect chimney sending buffer GPADL to the primary channel.
257 * Only primary channel has chimney sending buffer connected to it.
258 * Sub-channels just share this chimney sending buffer.
260 error = vmbus_chan_gpadl_connect(sc->hn_prichan,
261 sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE,
264 if_printf(sc->hn_ifp, "chimney sending buffer gpadl "
265 "connect failed: %d\n", error);
270 * Connect chimney sending buffer to NVS
273 xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim));
275 if_printf(sc->hn_ifp, "no xact for nvs chim conn\n");
279 chim = vmbus_xact_req_data(xact);
280 chim->nvs_type = HN_NVS_TYPE_CHIM_CONN;
281 chim->nvs_gpadl = sc->hn_chim_gpadl;
282 chim->nvs_sig = HN_NVS_CHIM_SIG;
284 resp_len = sizeof(*resp);
285 resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len,
286 HN_NVS_TYPE_CHIM_CONNRESP);
288 if_printf(sc->hn_ifp, "exec chim conn failed\n");
293 status = resp->nvs_status;
294 sectsz = resp->nvs_sectsz;
295 vmbus_xact_put(xact);
298 if (status != HN_NVS_STATUS_OK) {
299 if_printf(sc->hn_ifp, "chim conn failed: %x\n", status);
304 if_printf(sc->hn_ifp, "zero chimney sending buffer "
309 sc->hn_chim_szmax = sectsz;
310 sc->hn_chim_cnt = NETVSC_SEND_BUFFER_SIZE / sc->hn_chim_szmax;
311 if (NETVSC_SEND_BUFFER_SIZE % sc->hn_chim_szmax != 0) {
312 if_printf(sc->hn_ifp, "chimney sending sections are "
313 "not properly aligned\n");
315 if (sc->hn_chim_cnt % LONG_BIT != 0) {
316 if_printf(sc->hn_ifp, "discard %d chimney sending sections\n",
317 sc->hn_chim_cnt % LONG_BIT);
320 sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT;
321 sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long),
322 M_NETVSC, M_WAITOK | M_ZERO);
325 sc->hn_flags |= HN_FLAG_CHIM_CONNECTED;
327 if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n",
328 sc->hn_chim_szmax, sc->hn_chim_cnt);
334 vmbus_xact_put(xact);
335 hv_nv_destroy_send_buffer(sc);
340 * Net VSC destroy receive buffer
343 hv_nv_destroy_rx_buffer(struct hn_softc *sc)
347 if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) {
348 struct hn_nvs_rxbuf_disconn disconn;
351 * Disconnect RXBUF from NVS.
353 memset(&disconn, 0, sizeof(disconn));
354 disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN;
355 disconn.nvs_sig = HN_NVS_RXBUF_SIG;
357 /* NOTE: No response. */
358 ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
360 if_printf(sc->hn_ifp,
361 "send rxbuf disconn failed: %d\n", ret);
364 sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED;
367 if (sc->hn_rxbuf_gpadl != 0) {
369 * Disconnect RXBUF from primary channel.
371 ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
374 if_printf(sc->hn_ifp,
375 "rxbuf disconn failed: %d\n", ret);
378 sc->hn_rxbuf_gpadl = 0;
384 * Net VSC destroy send buffer
387 hv_nv_destroy_send_buffer(struct hn_softc *sc)
391 if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) {
392 struct hn_nvs_chim_disconn disconn;
395 * Disconnect chimney sending buffer from NVS.
397 memset(&disconn, 0, sizeof(disconn));
398 disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN;
399 disconn.nvs_sig = HN_NVS_CHIM_SIG;
401 /* NOTE: No response. */
402 ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn));
404 if_printf(sc->hn_ifp,
405 "send chim disconn failed: %d\n", ret);
408 sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED;
411 if (sc->hn_chim_gpadl != 0) {
413 * Disconnect chimney sending buffer from primary channel.
415 ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan,
418 if_printf(sc->hn_ifp,
419 "chim disconn failed: %d\n", ret);
422 sc->hn_chim_gpadl = 0;
425 if (sc->hn_chim_bmap != NULL) {
426 free(sc->hn_chim_bmap, M_NETVSC);
427 sc->hn_chim_bmap = NULL;
434 hn_nvs_doinit(struct hn_softc *sc, uint32_t nvs_ver)
436 struct vmbus_xact *xact;
437 struct hn_nvs_init *init;
438 const struct hn_nvs_init_resp *resp;
442 xact = vmbus_xact_get(sc->hn_xact, sizeof(*init));
444 if_printf(sc->hn_ifp, "no xact for nvs init\n");
447 init = vmbus_xact_req_data(xact);
448 init->nvs_type = HN_NVS_TYPE_INIT;
449 init->nvs_ver_min = nvs_ver;
450 init->nvs_ver_max = nvs_ver;
452 resp_len = sizeof(*resp);
453 resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len,
454 HN_NVS_TYPE_INIT_RESP);
456 if_printf(sc->hn_ifp, "exec init failed\n");
457 vmbus_xact_put(xact);
461 status = resp->nvs_status;
462 vmbus_xact_put(xact);
464 if (status != HN_NVS_STATUS_OK) {
465 if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n",
473 * Configure MTU and enable VLAN.
476 hn_nvs_conf_ndis(struct hn_softc *sc, int mtu)
478 struct hn_nvs_ndis_conf conf;
481 memset(&conf, 0, sizeof(conf));
482 conf.nvs_type = HN_NVS_TYPE_NDIS_CONF;
484 conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN;
486 /* NOTE: No response. */
487 error = hn_nvs_req_send(sc, &conf, sizeof(conf));
489 if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error);
494 hn_nvs_init_ndis(struct hn_softc *sc)
496 struct hn_nvs_ndis_init ndis;
499 memset(&ndis, 0, sizeof(ndis));
500 ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT;
501 ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver);
502 ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver);
504 /* NOTE: No response. */
505 error = hn_nvs_req_send(sc, &ndis, sizeof(ndis));
507 if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error);
512 hn_nvs_init(struct hn_softc *sc)
516 for (i = 0; i < nitems(hn_nvs_version); ++i) {
519 error = hn_nvs_doinit(sc, hn_nvs_version[i]);
521 sc->hn_nvs_ver = hn_nvs_version[i];
523 /* Set NDIS version according to NVS version. */
524 sc->hn_ndis_ver = HN_NDIS_VERSION_6_30;
525 if (sc->hn_nvs_ver <= HN_NVS_VERSION_4)
526 sc->hn_ndis_ver = HN_NDIS_VERSION_6_1;
529 if_printf(sc->hn_ifp, "NVS version 0x%x, "
530 "NDIS version %u.%u\n", sc->hn_nvs_ver,
531 HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver),
532 HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver));
537 if_printf(sc->hn_ifp, "no NVS available\n");
542 hv_nv_connect_to_vsp(struct hn_softc *sc, int mtu)
549 ret = hn_nvs_init(sc);
553 if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) {
555 * Configure NDIS before initializing it.
557 ret = hn_nvs_conf_ndis(sc, mtu);
565 ret = hn_nvs_init_ndis(sc);
569 ret = hv_nv_init_rx_buffer_with_net_vsp(sc);
571 ret = hv_nv_init_send_buffer_with_net_vsp(sc);
576 * Net VSC disconnect from VSP
579 hv_nv_disconnect_from_vsp(struct hn_softc *sc)
581 hv_nv_destroy_rx_buffer(sc);
582 hv_nv_destroy_send_buffer(sc);
586 * Net VSC on device add
588 * Callback when the device belonging to this driver is added
591 hv_nv_on_device_add(struct hn_softc *sc, int mtu)
595 * Connect with the NetVsp
597 return (hv_nv_connect_to_vsp(sc, mtu));
601 * Net VSC on device remove
604 hv_nv_on_device_remove(struct hn_softc *sc)
607 hv_nv_disconnect_from_vsp(sc);
609 /* Now, we can close the channel safely */
611 vmbus_chan_close(sc->hn_prichan);
617 hn_nvs_sent_xact(struct hn_send_ctx *sndc,
618 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
619 const void *data, int dlen)
622 vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen);
626 hn_nvs_sent_none(struct hn_send_ctx *sndc __unused,
627 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused,
628 const void *data __unused, int dlen __unused)
634 hn_chim_free(struct hn_softc *sc, uint32_t chim_idx)
639 idx = chim_idx / LONG_BIT;
640 KASSERT(idx < sc->hn_chim_bmap_cnt,
641 ("invalid chimney index 0x%x", chim_idx));
643 mask = 1UL << (chim_idx % LONG_BIT);
644 KASSERT(sc->hn_chim_bmap[idx] & mask,
645 ("index bitmap 0x%lx, chimney index %u, "
646 "bitmap idx %d, bitmask 0x%lx",
647 sc->hn_chim_bmap[idx], chim_idx, idx, mask));
649 atomic_clear_long(&sc->hn_chim_bmap[idx], mask);
654 * Sends a packet on the specified Hyper-V device.
655 * Returns 0 on success, non-zero on failure.
658 hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype,
659 struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt)
661 struct hn_nvs_rndis rndis;
664 rndis.nvs_type = HN_NVS_TYPE_RNDIS;
665 rndis.nvs_rndis_mtype = rndis_mtype;
666 rndis.nvs_chim_idx = sndc->hn_chim_idx;
667 rndis.nvs_chim_sz = sndc->hn_chim_sz;
670 ret = hn_nvs_send_sglist(chan, gpa, gpa_cnt,
671 &rndis, sizeof(rndis), sndc);
673 ret = hn_nvs_send(chan, VMBUS_CHANPKT_FLAG_RC,
674 &rndis, sizeof(rndis), sndc);