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