hn_nvs.c revision 307181
1/*- 2 * Copyright (c) 2009-2012,2016 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 * $FreeBSD: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c 307181 2016-10-13 06:17:33Z sephe $ 29 */ 30 31/** 32 * HyperV vmbus network VSC (virtual services client) module 33 * 34 */ 35 36 37#include <sys/param.h> 38#include <sys/kernel.h> 39#include <sys/socket.h> 40#include <sys/limits.h> 41#include <sys/lock.h> 42#include <net/if.h> 43#include <net/if_arp.h> 44#include <machine/bus.h> 45#include <machine/atomic.h> 46 47#include <dev/hyperv/include/hyperv.h> 48#include <dev/hyperv/include/vmbus_xact.h> 49#include <dev/hyperv/netvsc/hv_net_vsc.h> 50#include <dev/hyperv/netvsc/hv_rndis.h> 51#include <dev/hyperv/netvsc/hv_rndis_filter.h> 52#include <dev/hyperv/netvsc/if_hnreg.h> 53 54MALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); 55 56/* 57 * Forward declarations 58 */ 59static void hv_nv_on_channel_callback(struct vmbus_channel *chan, 60 void *xrxr); 61static int hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc); 62static int hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *, int); 63static int hv_nv_destroy_send_buffer(struct hn_softc *sc); 64static int hv_nv_destroy_rx_buffer(struct hn_softc *sc); 65static int hv_nv_connect_to_vsp(struct hn_softc *sc); 66static void hv_nv_on_send_completion(struct hn_softc *sc, 67 struct vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt); 68static void hv_nv_on_receive_completion(struct vmbus_channel *chan, 69 uint64_t tid); 70static void hv_nv_on_receive(struct hn_softc *sc, 71 struct hn_rx_ring *rxr, struct vmbus_channel *chan, 72 const struct vmbus_chanpkt_hdr *pkt); 73static void hn_nvs_sent_none(struct hn_send_ctx *sndc, 74 struct hn_softc *, struct vmbus_channel *chan, 75 const void *, int); 76static void hn_nvs_sent_xact(struct hn_send_ctx *, struct hn_softc *sc, 77 struct vmbus_channel *, const void *, int); 78 79struct hn_send_ctx hn_send_ctx_none = 80 HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL); 81 82uint32_t 83hn_chim_alloc(struct hn_softc *sc) 84{ 85 int i, bmap_cnt = sc->hn_chim_bmap_cnt; 86 u_long *bmap = sc->hn_chim_bmap; 87 uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 88 89 for (i = 0; i < bmap_cnt; ++i) { 90 int idx; 91 92 idx = ffsl(~bmap[i]); 93 if (idx == 0) 94 continue; 95 96 --idx; /* ffsl is 1-based */ 97 KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 98 ("invalid i %d and idx %d", i, idx)); 99 100 if (atomic_testandset_long(&bmap[i], idx)) 101 continue; 102 103 ret = i * LONG_BIT + idx; 104 break; 105 } 106 return (ret); 107} 108 109const void * 110hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, 111 void *req, int reqlen, size_t *resp_len) 112{ 113 struct hn_send_ctx sndc; 114 int error; 115 116 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact); 117 vmbus_xact_activate(xact); 118 119 error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC, 120 req, reqlen, &sndc); 121 if (error) { 122 vmbus_xact_deactivate(xact); 123 return NULL; 124 } 125 return (vmbus_xact_wait(xact, resp_len)); 126} 127 128static __inline int 129hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen) 130{ 131 132 return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE, 133 req, reqlen, &hn_send_ctx_none)); 134} 135 136/* 137 * Net VSC initialize receive buffer with net VSP 138 * 139 * Net VSP: Network virtual services client, also known as the 140 * Hyper-V extensible switch and the synthetic data path. 141 */ 142static int 143hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc, int rxbuf_size) 144{ 145 struct vmbus_xact *xact = NULL; 146 struct hn_nvs_rxbuf_conn *conn; 147 const struct hn_nvs_rxbuf_connresp *resp; 148 size_t resp_len; 149 uint32_t status; 150 int error; 151 152 KASSERT(rxbuf_size <= NETVSC_RECEIVE_BUFFER_SIZE, 153 ("invalid rxbuf size %d", rxbuf_size)); 154 155 /* 156 * Connect the RXBUF GPADL to the primary channel. 157 * 158 * NOTE: 159 * Only primary channel has RXBUF connected to it. Sub-channels 160 * just share this RXBUF. 161 */ 162 error = vmbus_chan_gpadl_connect(sc->hn_prichan, 163 sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl); 164 if (error) { 165 if_printf(sc->hn_ifp, "rxbuf gpadl connect failed: %d\n", 166 error); 167 goto cleanup; 168 } 169 170 /* 171 * Connect RXBUF to NVS. 172 */ 173 174 xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn)); 175 if (xact == NULL) { 176 if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n"); 177 error = ENXIO; 178 goto cleanup; 179 } 180 conn = vmbus_xact_req_data(xact); 181 conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN; 182 conn->nvs_gpadl = sc->hn_rxbuf_gpadl; 183 conn->nvs_sig = HN_NVS_RXBUF_SIG; 184 185 resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len); 186 if (resp == NULL) { 187 if_printf(sc->hn_ifp, "exec rxbuf conn failed\n"); 188 error = EIO; 189 goto cleanup; 190 } 191 if (resp_len < sizeof(*resp)) { 192 if_printf(sc->hn_ifp, "invalid rxbuf conn resp length %zu\n", 193 resp_len); 194 error = EINVAL; 195 goto cleanup; 196 } 197 if (resp->nvs_type != HN_NVS_TYPE_RXBUF_CONNRESP) { 198 if_printf(sc->hn_ifp, "not rxbuf conn resp, type %u\n", 199 resp->nvs_type); 200 error = EINVAL; 201 goto cleanup; 202 } 203 204 status = resp->nvs_status; 205 vmbus_xact_put(xact); 206 xact = NULL; 207 208 if (status != HN_NVS_STATUS_OK) { 209 if_printf(sc->hn_ifp, "rxbuf conn failed: %x\n", status); 210 error = EIO; 211 goto cleanup; 212 } 213 sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED; 214 215 return (0); 216 217cleanup: 218 if (xact != NULL) 219 vmbus_xact_put(xact); 220 hv_nv_destroy_rx_buffer(sc); 221 return (error); 222} 223 224/* 225 * Net VSC initialize send buffer with net VSP 226 */ 227static int 228hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc) 229{ 230 struct vmbus_xact *xact = NULL; 231 struct hn_nvs_chim_conn *chim; 232 const struct hn_nvs_chim_connresp *resp; 233 size_t resp_len; 234 uint32_t status, sectsz; 235 int error; 236 237 /* 238 * Connect chimney sending buffer GPADL to the primary channel. 239 * 240 * NOTE: 241 * Only primary channel has chimney sending buffer connected to it. 242 * Sub-channels just share this chimney sending buffer. 243 */ 244 error = vmbus_chan_gpadl_connect(sc->hn_prichan, 245 sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE, 246 &sc->hn_chim_gpadl); 247 if (error) { 248 if_printf(sc->hn_ifp, "chimney sending buffer gpadl " 249 "connect failed: %d\n", error); 250 goto cleanup; 251 } 252 253 /* 254 * Connect chimney sending buffer to NVS 255 */ 256 257 xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim)); 258 if (xact == NULL) { 259 if_printf(sc->hn_ifp, "no xact for nvs chim conn\n"); 260 error = ENXIO; 261 goto cleanup; 262 } 263 chim = vmbus_xact_req_data(xact); 264 chim->nvs_type = HN_NVS_TYPE_CHIM_CONN; 265 chim->nvs_gpadl = sc->hn_chim_gpadl; 266 chim->nvs_sig = HN_NVS_CHIM_SIG; 267 268 resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len); 269 if (resp == NULL) { 270 if_printf(sc->hn_ifp, "exec chim conn failed\n"); 271 error = EIO; 272 goto cleanup; 273 } 274 if (resp_len < sizeof(*resp)) { 275 if_printf(sc->hn_ifp, "invalid chim conn resp length %zu\n", 276 resp_len); 277 error = EINVAL; 278 goto cleanup; 279 } 280 if (resp->nvs_type != HN_NVS_TYPE_CHIM_CONNRESP) { 281 if_printf(sc->hn_ifp, "not chim conn resp, type %u\n", 282 resp->nvs_type); 283 error = EINVAL; 284 goto cleanup; 285 } 286 287 status = resp->nvs_status; 288 sectsz = resp->nvs_sectsz; 289 vmbus_xact_put(xact); 290 xact = NULL; 291 292 if (status != HN_NVS_STATUS_OK) { 293 if_printf(sc->hn_ifp, "chim conn failed: %x\n", status); 294 error = EIO; 295 goto cleanup; 296 } 297 if (sectsz == 0) { 298 if_printf(sc->hn_ifp, "zero chimney sending buffer " 299 "section size\n"); 300 return 0; 301 } 302 303 sc->hn_chim_szmax = sectsz; 304 sc->hn_chim_cnt = NETVSC_SEND_BUFFER_SIZE / sc->hn_chim_szmax; 305 if (NETVSC_SEND_BUFFER_SIZE % sc->hn_chim_szmax != 0) { 306 if_printf(sc->hn_ifp, "chimney sending sections are " 307 "not properly aligned\n"); 308 } 309 if (sc->hn_chim_cnt % LONG_BIT != 0) { 310 if_printf(sc->hn_ifp, "discard %d chimney sending sections\n", 311 sc->hn_chim_cnt % LONG_BIT); 312 } 313 314 sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT; 315 sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long), 316 M_NETVSC, M_WAITOK | M_ZERO); 317 318 /* Done! */ 319 sc->hn_flags |= HN_FLAG_CHIM_CONNECTED; 320 if (bootverbose) { 321 if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n", 322 sc->hn_chim_szmax, sc->hn_chim_cnt); 323 } 324 return 0; 325 326cleanup: 327 if (xact != NULL) 328 vmbus_xact_put(xact); 329 hv_nv_destroy_send_buffer(sc); 330 return (error); 331} 332 333/* 334 * Net VSC destroy receive buffer 335 */ 336static int 337hv_nv_destroy_rx_buffer(struct hn_softc *sc) 338{ 339 int ret = 0; 340 341 if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) { 342 struct hn_nvs_rxbuf_disconn disconn; 343 344 /* 345 * Disconnect RXBUF from NVS. 346 */ 347 memset(&disconn, 0, sizeof(disconn)); 348 disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN; 349 disconn.nvs_sig = HN_NVS_RXBUF_SIG; 350 351 /* NOTE: No response. */ 352 ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn)); 353 if (ret != 0) { 354 if_printf(sc->hn_ifp, 355 "send rxbuf disconn failed: %d\n", ret); 356 return (ret); 357 } 358 sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED; 359 } 360 361 if (sc->hn_rxbuf_gpadl != 0) { 362 /* 363 * Disconnect RXBUF from primary channel. 364 */ 365 ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 366 sc->hn_rxbuf_gpadl); 367 if (ret != 0) { 368 if_printf(sc->hn_ifp, 369 "rxbuf disconn failed: %d\n", ret); 370 return (ret); 371 } 372 sc->hn_rxbuf_gpadl = 0; 373 } 374 return (ret); 375} 376 377/* 378 * Net VSC destroy send buffer 379 */ 380static int 381hv_nv_destroy_send_buffer(struct hn_softc *sc) 382{ 383 int ret = 0; 384 385 if (sc->hn_flags & HN_FLAG_CHIM_CONNECTED) { 386 struct hn_nvs_chim_disconn disconn; 387 388 /* 389 * Disconnect chimney sending buffer from NVS. 390 */ 391 memset(&disconn, 0, sizeof(disconn)); 392 disconn.nvs_type = HN_NVS_TYPE_CHIM_DISCONN; 393 disconn.nvs_sig = HN_NVS_CHIM_SIG; 394 395 /* NOTE: No response. */ 396 ret = hn_nvs_req_send(sc, &disconn, sizeof(disconn)); 397 if (ret != 0) { 398 if_printf(sc->hn_ifp, 399 "send chim disconn failed: %d\n", ret); 400 return (ret); 401 } 402 sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED; 403 } 404 405 if (sc->hn_chim_gpadl != 0) { 406 /* 407 * Disconnect chimney sending buffer from primary channel. 408 */ 409 ret = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 410 sc->hn_chim_gpadl); 411 if (ret != 0) { 412 if_printf(sc->hn_ifp, 413 "chim disconn failed: %d\n", ret); 414 return (ret); 415 } 416 sc->hn_chim_gpadl = 0; 417 } 418 419 if (sc->hn_chim_bmap != NULL) { 420 free(sc->hn_chim_bmap, M_NETVSC); 421 sc->hn_chim_bmap = NULL; 422 } 423 424 return (ret); 425} 426 427static int 428hv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, uint32_t nvs_ver) 429{ 430 struct vmbus_xact *xact; 431 struct hn_nvs_init *init; 432 const struct hn_nvs_init_resp *resp; 433 size_t resp_len; 434 uint32_t status; 435 436 xact = vmbus_xact_get(sc->hn_xact, sizeof(*init)); 437 if (xact == NULL) { 438 if_printf(sc->hn_ifp, "no xact for nvs init\n"); 439 return (ENXIO); 440 } 441 init = vmbus_xact_req_data(xact); 442 init->nvs_type = HN_NVS_TYPE_INIT; 443 init->nvs_ver_min = nvs_ver; 444 init->nvs_ver_max = nvs_ver; 445 446 resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len); 447 if (resp == NULL) { 448 if_printf(sc->hn_ifp, "exec init failed\n"); 449 vmbus_xact_put(xact); 450 return (EIO); 451 } 452 if (resp_len < sizeof(*resp)) { 453 if_printf(sc->hn_ifp, "invalid init resp length %zu\n", 454 resp_len); 455 vmbus_xact_put(xact); 456 return (EINVAL); 457 } 458 if (resp->nvs_type != HN_NVS_TYPE_INIT_RESP) { 459 if_printf(sc->hn_ifp, "not init resp, type %u\n", 460 resp->nvs_type); 461 vmbus_xact_put(xact); 462 return (EINVAL); 463 } 464 465 status = resp->nvs_status; 466 vmbus_xact_put(xact); 467 468 if (status != HN_NVS_STATUS_OK) { 469 if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n", 470 nvs_ver); 471 return (EINVAL); 472 } 473 return (0); 474} 475 476/* 477 * Send NDIS version 2 config packet containing MTU. 478 * 479 * Not valid for NDIS version 1. 480 */ 481static int 482hv_nv_send_ndis_config(struct hn_softc *sc, uint32_t mtu) 483{ 484 struct hn_nvs_ndis_conf conf; 485 int error; 486 487 memset(&conf, 0, sizeof(conf)); 488 conf.nvs_type = HN_NVS_TYPE_NDIS_CONF; 489 conf.nvs_mtu = mtu; 490 conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN; 491 492 /* NOTE: No response. */ 493 error = hn_nvs_req_send(sc, &conf, sizeof(conf)); 494 if (error) 495 if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error); 496 return (error); 497} 498 499/* 500 * Net VSC connect to VSP 501 */ 502static int 503hv_nv_connect_to_vsp(struct hn_softc *sc) 504{ 505 uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1, 506 NVSP_PROTOCOL_VERSION_2, 507 NVSP_PROTOCOL_VERSION_4, 508 NVSP_PROTOCOL_VERSION_5 }; 509 int i; 510 int protocol_number = nitems(protocol_list); 511 int ret = 0; 512 device_t dev = sc->hn_dev; 513 struct ifnet *ifp = sc->arpcom.ac_ifp; 514 struct hn_nvs_ndis_init ndis; 515 int rxbuf_size; 516 517 /* 518 * Negotiate the NVSP version. Try the latest NVSP first. 519 */ 520 for (i = protocol_number - 1; i >= 0; i--) { 521 if (hv_nv_negotiate_nvsp_protocol(sc, protocol_list[i]) == 0) { 522 sc->hn_nvs_ver = protocol_list[i]; 523 sc->hn_ndis_ver = NDIS_VERSION_6_30; 524 if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_4) 525 sc->hn_ndis_ver = NDIS_VERSION_6_1; 526 if (bootverbose) { 527 if_printf(sc->hn_ifp, "NVS version 0x%x, " 528 "NDIS version %u.%u\n", 529 sc->hn_nvs_ver, 530 NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 531 NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 532 } 533 break; 534 } 535 } 536 537 if (i < 0) { 538 if (bootverbose) 539 device_printf(dev, "failed to negotiate a valid " 540 "protocol.\n"); 541 return (EPROTO); 542 } 543 544 /* 545 * Set the MTU if supported by this NVSP protocol version 546 * This needs to be right after the NVSP init message per Haiyang 547 */ 548 if (sc->hn_nvs_ver >= NVSP_PROTOCOL_VERSION_2) 549 ret = hv_nv_send_ndis_config(sc, ifp->if_mtu); 550 551 /* 552 * Initialize NDIS. 553 */ 554 555 memset(&ndis, 0, sizeof(ndis)); 556 ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT; 557 ndis.nvs_ndis_major = NDIS_VERSION_MAJOR(sc->hn_ndis_ver); 558 ndis.nvs_ndis_minor = NDIS_VERSION_MINOR(sc->hn_ndis_ver); 559 560 /* NOTE: No response. */ 561 ret = hn_nvs_req_send(sc, &ndis, sizeof(ndis)); 562 if (ret != 0) { 563 if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", ret); 564 goto cleanup; 565 } 566 567 /* Post the big receive buffer to NetVSP */ 568 if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_2) 569 rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; 570 else 571 rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE; 572 573 ret = hv_nv_init_rx_buffer_with_net_vsp(sc, rxbuf_size); 574 if (ret == 0) 575 ret = hv_nv_init_send_buffer_with_net_vsp(sc); 576 577cleanup: 578 return (ret); 579} 580 581/* 582 * Net VSC disconnect from VSP 583 */ 584static void 585hv_nv_disconnect_from_vsp(struct hn_softc *sc) 586{ 587 hv_nv_destroy_rx_buffer(sc); 588 hv_nv_destroy_send_buffer(sc); 589} 590 591void 592hv_nv_subchan_attach(struct vmbus_channel *chan, struct hn_rx_ring *rxr) 593{ 594 KASSERT(rxr->hn_rx_idx == vmbus_chan_subidx(chan), 595 ("chan%u subidx %u, rxr%d mismatch", 596 vmbus_chan_id(chan), vmbus_chan_subidx(chan), rxr->hn_rx_idx)); 597 vmbus_chan_open(chan, NETVSC_DEVICE_RING_BUFFER_SIZE, 598 NETVSC_DEVICE_RING_BUFFER_SIZE, NULL, 0, 599 hv_nv_on_channel_callback, rxr); 600} 601 602/* 603 * Net VSC on device add 604 * 605 * Callback when the device belonging to this driver is added 606 */ 607int 608hv_nv_on_device_add(struct hn_softc *sc, struct hn_rx_ring *rxr) 609{ 610 struct vmbus_channel *chan = sc->hn_prichan; 611 int ret = 0; 612 613 /* 614 * Open the channel 615 */ 616 KASSERT(rxr->hn_rx_idx == vmbus_chan_subidx(chan), 617 ("chan%u subidx %u, rxr%d mismatch", 618 vmbus_chan_id(chan), vmbus_chan_subidx(chan), rxr->hn_rx_idx)); 619 ret = vmbus_chan_open(chan, 620 NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE, 621 NULL, 0, hv_nv_on_channel_callback, rxr); 622 if (ret != 0) 623 goto cleanup; 624 625 /* 626 * Connect with the NetVsp 627 */ 628 ret = hv_nv_connect_to_vsp(sc); 629 if (ret != 0) 630 goto close; 631 632 return (0); 633 634close: 635 /* Now, we can close the channel safely */ 636 vmbus_chan_close(chan); 637cleanup: 638 return (ret); 639} 640 641/* 642 * Net VSC on device remove 643 */ 644int 645hv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel) 646{ 647 648 hv_nv_disconnect_from_vsp(sc); 649 650 /* Now, we can close the channel safely */ 651 652 vmbus_chan_close(sc->hn_prichan); 653 654 return (0); 655} 656 657static void 658hn_nvs_sent_xact(struct hn_send_ctx *sndc, 659 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, 660 const void *data, int dlen) 661{ 662 663 vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen); 664} 665 666static void 667hn_nvs_sent_none(struct hn_send_ctx *sndc __unused, 668 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, 669 const void *data __unused, int dlen __unused) 670{ 671 /* EMPTY */ 672} 673 674void 675hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 676{ 677 u_long mask; 678 uint32_t idx; 679 680 idx = chim_idx / LONG_BIT; 681 KASSERT(idx < sc->hn_chim_bmap_cnt, 682 ("invalid chimney index 0x%x", chim_idx)); 683 684 mask = 1UL << (chim_idx % LONG_BIT); 685 KASSERT(sc->hn_chim_bmap[idx] & mask, 686 ("index bitmap 0x%lx, chimney index %u, " 687 "bitmap idx %d, bitmask 0x%lx", 688 sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 689 690 atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 691} 692 693/* 694 * Net VSC on send completion 695 */ 696static void 697hv_nv_on_send_completion(struct hn_softc *sc, struct vmbus_channel *chan, 698 const struct vmbus_chanpkt_hdr *pkt) 699{ 700 struct hn_send_ctx *sndc; 701 702 sndc = (struct hn_send_ctx *)(uintptr_t)pkt->cph_xactid; 703 sndc->hn_cb(sndc, sc, chan, VMBUS_CHANPKT_CONST_DATA(pkt), 704 VMBUS_CHANPKT_DATALEN(pkt)); 705 /* 706 * NOTE: 707 * 'sndc' CAN NOT be accessed anymore, since it can be freed by 708 * its callback. 709 */ 710} 711 712/* 713 * Net VSC on send 714 * Sends a packet on the specified Hyper-V device. 715 * Returns 0 on success, non-zero on failure. 716 */ 717int 718hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype, 719 struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt) 720{ 721 struct hn_nvs_rndis rndis; 722 int ret; 723 724 rndis.nvs_type = HN_NVS_TYPE_RNDIS; 725 rndis.nvs_rndis_mtype = rndis_mtype; 726 rndis.nvs_chim_idx = sndc->hn_chim_idx; 727 rndis.nvs_chim_sz = sndc->hn_chim_sz; 728 729 if (gpa_cnt) { 730 ret = hn_nvs_send_sglist(chan, gpa, gpa_cnt, 731 &rndis, sizeof(rndis), sndc); 732 } else { 733 ret = hn_nvs_send(chan, VMBUS_CHANPKT_FLAG_RC, 734 &rndis, sizeof(rndis), sndc); 735 } 736 737 return (ret); 738} 739 740/* 741 * Net VSC on receive 742 * 743 * In the FreeBSD Hyper-V virtual world, this function deals exclusively 744 * with virtual addresses. 745 */ 746static void 747hv_nv_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr, 748 struct vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr) 749{ 750 const struct vmbus_chanpkt_rxbuf *pkt; 751 const struct hn_nvs_hdr *nvs_hdr; 752 int count = 0; 753 int i = 0; 754 755 /* Make sure that this is a RNDIS message. */ 756 nvs_hdr = VMBUS_CHANPKT_CONST_DATA(pkthdr); 757 if (__predict_false(nvs_hdr->nvs_type != HN_NVS_TYPE_RNDIS)) { 758 if_printf(rxr->hn_ifp, "nvs type %u, not RNDIS\n", 759 nvs_hdr->nvs_type); 760 return; 761 } 762 763 pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 764 765 if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) { 766 if_printf(rxr->hn_ifp, "rxbuf_id %d is invalid!\n", 767 pkt->cp_rxbuf_id); 768 return; 769 } 770 771 count = pkt->cp_rxbuf_cnt; 772 773 /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 774 for (i = 0; i < count; i++) { 775 hv_rf_on_receive(sc, rxr, 776 rxr->hn_rxbuf + pkt->cp_rxbuf[i].rb_ofs, 777 pkt->cp_rxbuf[i].rb_len); 778 } 779 780 /* 781 * Moved completion call back here so that all received 782 * messages (not just data messages) will trigger a response 783 * message back to the host. 784 */ 785 hv_nv_on_receive_completion(chan, pkt->cp_hdr.cph_xactid); 786} 787 788/* 789 * Net VSC on receive completion 790 * 791 * Send a receive completion packet to RNDIS device (ie NetVsp) 792 */ 793static void 794hv_nv_on_receive_completion(struct vmbus_channel *chan, uint64_t tid) 795{ 796 struct hn_nvs_rndis_ack ack; 797 int retries = 0; 798 int ret = 0; 799 800 ack.nvs_type = HN_NVS_TYPE_RNDIS_ACK; 801 ack.nvs_status = HN_NVS_STATUS_OK; 802 803retry_send_cmplt: 804 /* Send the completion */ 805 ret = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 806 VMBUS_CHANPKT_FLAG_NONE, &ack, sizeof(ack), tid); 807 if (ret == 0) { 808 /* success */ 809 /* no-op */ 810 } else if (ret == EAGAIN) { 811 /* no more room... wait a bit and attempt to retry 3 times */ 812 retries++; 813 814 if (retries < 4) { 815 DELAY(100); 816 goto retry_send_cmplt; 817 } 818 } 819} 820 821static void 822hn_proc_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 823{ 824 const struct hn_nvs_hdr *hdr; 825 826 hdr = VMBUS_CHANPKT_CONST_DATA(pkt); 827 if (hdr->nvs_type == HN_NVS_TYPE_TXTBL_NOTE) { 828 /* Useless; ignore */ 829 return; 830 } 831 if_printf(sc->hn_ifp, "got notify, nvs type %u\n", hdr->nvs_type); 832} 833 834/* 835 * Net VSC on channel callback 836 */ 837static void 838hv_nv_on_channel_callback(struct vmbus_channel *chan, void *xrxr) 839{ 840 struct hn_rx_ring *rxr = xrxr; 841 struct hn_softc *sc = rxr->hn_ifp->if_softc; 842 void *buffer; 843 int bufferlen = NETVSC_PACKET_SIZE; 844 845 buffer = rxr->hn_rdbuf; 846 do { 847 struct vmbus_chanpkt_hdr *pkt = buffer; 848 uint32_t bytes_rxed; 849 int ret; 850 851 bytes_rxed = bufferlen; 852 ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed); 853 if (ret == 0) { 854 if (bytes_rxed > 0) { 855 switch (pkt->cph_type) { 856 case VMBUS_CHANPKT_TYPE_COMP: 857 hv_nv_on_send_completion(sc, chan, pkt); 858 break; 859 case VMBUS_CHANPKT_TYPE_RXBUF: 860 hv_nv_on_receive(sc, rxr, chan, pkt); 861 break; 862 case VMBUS_CHANPKT_TYPE_INBAND: 863 hn_proc_notify(sc, pkt); 864 break; 865 default: 866 if_printf(rxr->hn_ifp, 867 "unknown chan pkt %u\n", 868 pkt->cph_type); 869 break; 870 } 871 } 872 } else if (ret == ENOBUFS) { 873 /* Handle large packet */ 874 if (bufferlen > NETVSC_PACKET_SIZE) { 875 free(buffer, M_NETVSC); 876 buffer = NULL; 877 } 878 879 /* alloc new buffer */ 880 buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT); 881 if (buffer == NULL) { 882 if_printf(rxr->hn_ifp, 883 "hv_cb malloc buffer failed, len=%u\n", 884 bytes_rxed); 885 bufferlen = 0; 886 break; 887 } 888 bufferlen = bytes_rxed; 889 } else { 890 /* No more packets */ 891 break; 892 } 893 } while (1); 894 895 if (bufferlen > NETVSC_PACKET_SIZE) 896 free(buffer, M_NETVSC); 897 898 hv_rf_channel_rollup(rxr, rxr->hn_txr); 899} 900