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