hn_nvs.c revision 307250
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 307250 2016-10-14 02:52:48Z 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 int hn_nvs_conn_chim(struct hn_softc *sc); 60static int hn_nvs_conn_rxbuf(struct hn_softc *); 61static int hn_nvs_disconn_chim(struct hn_softc *sc); 62static int hn_nvs_disconn_rxbuf(struct hn_softc *sc); 63static void hn_nvs_sent_none(struct hn_send_ctx *sndc, 64 struct hn_softc *, struct vmbus_channel *chan, 65 const void *, int); 66 67struct hn_send_ctx hn_send_ctx_none = 68 HN_SEND_CTX_INITIALIZER(hn_nvs_sent_none, NULL); 69 70static const uint32_t hn_nvs_version[] = { 71 HN_NVS_VERSION_5, 72 HN_NVS_VERSION_4, 73 HN_NVS_VERSION_2, 74 HN_NVS_VERSION_1 75}; 76 77uint32_t 78hn_chim_alloc(struct hn_softc *sc) 79{ 80 int i, bmap_cnt = sc->hn_chim_bmap_cnt; 81 u_long *bmap = sc->hn_chim_bmap; 82 uint32_t ret = HN_NVS_CHIM_IDX_INVALID; 83 84 for (i = 0; i < bmap_cnt; ++i) { 85 int idx; 86 87 idx = ffsl(~bmap[i]); 88 if (idx == 0) 89 continue; 90 91 --idx; /* ffsl is 1-based */ 92 KASSERT(i * LONG_BIT + idx < sc->hn_chim_cnt, 93 ("invalid i %d and idx %d", i, idx)); 94 95 if (atomic_testandset_long(&bmap[i], idx)) 96 continue; 97 98 ret = i * LONG_BIT + idx; 99 break; 100 } 101 return (ret); 102} 103 104static const void * 105hn_nvs_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, 106 void *req, int reqlen, size_t *resplen0, uint32_t type) 107{ 108 struct hn_send_ctx sndc; 109 size_t resplen, min_resplen = *resplen0; 110 const struct hn_nvs_hdr *hdr; 111 int error; 112 113 KASSERT(min_resplen >= sizeof(*hdr), 114 ("invalid minimum response len %zu", min_resplen)); 115 116 /* 117 * Execute the xact setup by the caller. 118 */ 119 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact); 120 121 vmbus_xact_activate(xact); 122 error = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC, 123 req, reqlen, &sndc); 124 if (error) { 125 vmbus_xact_deactivate(xact); 126 return (NULL); 127 } 128 hdr = vmbus_xact_wait(xact, &resplen); 129 130 /* 131 * Check this NVS response message. 132 */ 133 if (resplen < min_resplen) { 134 if_printf(sc->hn_ifp, "invalid NVS resp len %zu\n", resplen); 135 return (NULL); 136 } 137 if (hdr->nvs_type != type) { 138 if_printf(sc->hn_ifp, "unexpected NVS resp 0x%08x, " 139 "expect 0x%08x\n", hdr->nvs_type, type); 140 return (NULL); 141 } 142 /* All pass! */ 143 *resplen0 = resplen; 144 return (hdr); 145} 146 147static __inline int 148hn_nvs_req_send(struct hn_softc *sc, void *req, int reqlen) 149{ 150 151 return (hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_NONE, 152 req, reqlen, &hn_send_ctx_none)); 153} 154 155static int 156hn_nvs_conn_rxbuf(struct hn_softc *sc) 157{ 158 struct vmbus_xact *xact = NULL; 159 struct hn_nvs_rxbuf_conn *conn; 160 const struct hn_nvs_rxbuf_connresp *resp; 161 size_t resp_len; 162 uint32_t status; 163 int error, rxbuf_size; 164 165 /* 166 * Limit RXBUF size for old NVS. 167 */ 168 if (sc->hn_nvs_ver <= HN_NVS_VERSION_2) 169 rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; 170 else 171 rxbuf_size = NETVSC_RECEIVE_BUFFER_SIZE; 172 173 /* 174 * Connect the RXBUF GPADL to the primary channel. 175 * 176 * NOTE: 177 * Only primary channel has RXBUF connected to it. Sub-channels 178 * just share this RXBUF. 179 */ 180 error = vmbus_chan_gpadl_connect(sc->hn_prichan, 181 sc->hn_rxbuf_dma.hv_paddr, rxbuf_size, &sc->hn_rxbuf_gpadl); 182 if (error) { 183 if_printf(sc->hn_ifp, "rxbuf gpadl conn failed: %d\n", 184 error); 185 goto cleanup; 186 } 187 188 /* 189 * Connect RXBUF to NVS. 190 */ 191 192 xact = vmbus_xact_get(sc->hn_xact, sizeof(*conn)); 193 if (xact == NULL) { 194 if_printf(sc->hn_ifp, "no xact for nvs rxbuf conn\n"); 195 error = ENXIO; 196 goto cleanup; 197 } 198 conn = vmbus_xact_req_data(xact); 199 conn->nvs_type = HN_NVS_TYPE_RXBUF_CONN; 200 conn->nvs_gpadl = sc->hn_rxbuf_gpadl; 201 conn->nvs_sig = HN_NVS_RXBUF_SIG; 202 203 resp_len = sizeof(*resp); 204 resp = hn_nvs_xact_execute(sc, xact, conn, sizeof(*conn), &resp_len, 205 HN_NVS_TYPE_RXBUF_CONNRESP); 206 if (resp == NULL) { 207 if_printf(sc->hn_ifp, "exec nvs rxbuf conn failed\n"); 208 error = EIO; 209 goto cleanup; 210 } 211 212 status = resp->nvs_status; 213 vmbus_xact_put(xact); 214 xact = NULL; 215 216 if (status != HN_NVS_STATUS_OK) { 217 if_printf(sc->hn_ifp, "nvs rxbuf conn failed: %x\n", status); 218 error = EIO; 219 goto cleanup; 220 } 221 sc->hn_flags |= HN_FLAG_RXBUF_CONNECTED; 222 223 return (0); 224 225cleanup: 226 if (xact != NULL) 227 vmbus_xact_put(xact); 228 hn_nvs_disconn_rxbuf(sc); 229 return (error); 230} 231 232static int 233hn_nvs_conn_chim(struct hn_softc *sc) 234{ 235 struct vmbus_xact *xact = NULL; 236 struct hn_nvs_chim_conn *chim; 237 const struct hn_nvs_chim_connresp *resp; 238 size_t resp_len; 239 uint32_t status, sectsz; 240 int error; 241 242 /* 243 * Connect chimney sending buffer GPADL to the primary channel. 244 * 245 * NOTE: 246 * Only primary channel has chimney sending buffer connected to it. 247 * Sub-channels just share this chimney sending buffer. 248 */ 249 error = vmbus_chan_gpadl_connect(sc->hn_prichan, 250 sc->hn_chim_dma.hv_paddr, NETVSC_SEND_BUFFER_SIZE, 251 &sc->hn_chim_gpadl); 252 if (error) { 253 if_printf(sc->hn_ifp, "chim gpadl conn failed: %d\n", error); 254 goto cleanup; 255 } 256 257 /* 258 * Connect chimney sending buffer to NVS 259 */ 260 261 xact = vmbus_xact_get(sc->hn_xact, sizeof(*chim)); 262 if (xact == NULL) { 263 if_printf(sc->hn_ifp, "no xact for nvs chim conn\n"); 264 error = ENXIO; 265 goto cleanup; 266 } 267 chim = vmbus_xact_req_data(xact); 268 chim->nvs_type = HN_NVS_TYPE_CHIM_CONN; 269 chim->nvs_gpadl = sc->hn_chim_gpadl; 270 chim->nvs_sig = HN_NVS_CHIM_SIG; 271 272 resp_len = sizeof(*resp); 273 resp = hn_nvs_xact_execute(sc, xact, chim, sizeof(*chim), &resp_len, 274 HN_NVS_TYPE_CHIM_CONNRESP); 275 if (resp == NULL) { 276 if_printf(sc->hn_ifp, "exec nvs chim conn failed\n"); 277 error = EIO; 278 goto cleanup; 279 } 280 281 status = resp->nvs_status; 282 sectsz = resp->nvs_sectsz; 283 vmbus_xact_put(xact); 284 xact = NULL; 285 286 if (status != HN_NVS_STATUS_OK) { 287 if_printf(sc->hn_ifp, "nvs chim conn failed: %x\n", status); 288 error = EIO; 289 goto cleanup; 290 } 291 if (sectsz == 0) { 292 if_printf(sc->hn_ifp, "zero chimney sending buffer " 293 "section size\n"); 294 return (0); 295 } 296 297 sc->hn_chim_szmax = sectsz; 298 sc->hn_chim_cnt = NETVSC_SEND_BUFFER_SIZE / sc->hn_chim_szmax; 299 if (NETVSC_SEND_BUFFER_SIZE % sc->hn_chim_szmax != 0) { 300 if_printf(sc->hn_ifp, "chimney sending sections are " 301 "not properly aligned\n"); 302 } 303 if (sc->hn_chim_cnt % LONG_BIT != 0) { 304 if_printf(sc->hn_ifp, "discard %d chimney sending sections\n", 305 sc->hn_chim_cnt % LONG_BIT); 306 } 307 308 sc->hn_chim_bmap_cnt = sc->hn_chim_cnt / LONG_BIT; 309 sc->hn_chim_bmap = malloc(sc->hn_chim_bmap_cnt * sizeof(u_long), 310 M_NETVSC, M_WAITOK | M_ZERO); 311 312 /* Done! */ 313 sc->hn_flags |= HN_FLAG_CHIM_CONNECTED; 314 if (bootverbose) { 315 if_printf(sc->hn_ifp, "chimney sending buffer %d/%d\n", 316 sc->hn_chim_szmax, sc->hn_chim_cnt); 317 } 318 return (0); 319 320cleanup: 321 if (xact != NULL) 322 vmbus_xact_put(xact); 323 hn_nvs_disconn_chim(sc); 324 return (error); 325} 326 327static int 328hn_nvs_disconn_rxbuf(struct hn_softc *sc) 329{ 330 int error; 331 332 if (sc->hn_flags & HN_FLAG_RXBUF_CONNECTED) { 333 struct hn_nvs_rxbuf_disconn disconn; 334 335 /* 336 * Disconnect RXBUF from NVS. 337 */ 338 memset(&disconn, 0, sizeof(disconn)); 339 disconn.nvs_type = HN_NVS_TYPE_RXBUF_DISCONN; 340 disconn.nvs_sig = HN_NVS_RXBUF_SIG; 341 342 /* NOTE: No response. */ 343 error = hn_nvs_req_send(sc, &disconn, sizeof(disconn)); 344 if (error) { 345 if_printf(sc->hn_ifp, 346 "send nvs rxbuf disconn failed: %d\n", error); 347 return (error); 348 } 349 sc->hn_flags &= ~HN_FLAG_RXBUF_CONNECTED; 350 351 /* 352 * Wait for the hypervisor to receive this NVS request. 353 */ 354 while (!vmbus_chan_tx_empty(sc->hn_prichan)) 355 pause("waittx", 1); 356 /* 357 * Linger long enough for NVS to disconnect RXBUF. 358 */ 359 pause("lingtx", (200 * hz) / 1000); 360 } 361 362 if (sc->hn_rxbuf_gpadl != 0) { 363 /* 364 * Disconnect RXBUF from primary channel. 365 */ 366 error = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 367 sc->hn_rxbuf_gpadl); 368 if (error) { 369 if_printf(sc->hn_ifp, 370 "rxbuf gpadl disconn failed: %d\n", error); 371 return (error); 372 } 373 sc->hn_rxbuf_gpadl = 0; 374 } 375 return (0); 376} 377 378static int 379hn_nvs_disconn_chim(struct hn_softc *sc) 380{ 381 int error; 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 error = hn_nvs_req_send(sc, &disconn, sizeof(disconn)); 395 if (error) { 396 if_printf(sc->hn_ifp, 397 "send nvs chim disconn failed: %d\n", error); 398 return (error); 399 } 400 sc->hn_flags &= ~HN_FLAG_CHIM_CONNECTED; 401 402 /* 403 * Wait for the hypervisor to receive this NVS request. 404 */ 405 while (!vmbus_chan_tx_empty(sc->hn_prichan)) 406 pause("waittx", 1); 407 /* 408 * Linger long enough for NVS to disconnect chimney 409 * sending buffer. 410 */ 411 pause("lingtx", (200 * hz) / 1000); 412 } 413 414 if (sc->hn_chim_gpadl != 0) { 415 /* 416 * Disconnect chimney sending buffer from primary channel. 417 */ 418 error = vmbus_chan_gpadl_disconnect(sc->hn_prichan, 419 sc->hn_chim_gpadl); 420 if (error) { 421 if_printf(sc->hn_ifp, 422 "chim gpadl disconn failed: %d\n", error); 423 return (error); 424 } 425 sc->hn_chim_gpadl = 0; 426 } 427 428 if (sc->hn_chim_bmap != NULL) { 429 free(sc->hn_chim_bmap, M_NETVSC); 430 sc->hn_chim_bmap = NULL; 431 } 432 return (0); 433} 434 435static int 436hn_nvs_doinit(struct hn_softc *sc, uint32_t nvs_ver) 437{ 438 struct vmbus_xact *xact; 439 struct hn_nvs_init *init; 440 const struct hn_nvs_init_resp *resp; 441 size_t resp_len; 442 uint32_t status; 443 444 xact = vmbus_xact_get(sc->hn_xact, sizeof(*init)); 445 if (xact == NULL) { 446 if_printf(sc->hn_ifp, "no xact for nvs init\n"); 447 return (ENXIO); 448 } 449 init = vmbus_xact_req_data(xact); 450 init->nvs_type = HN_NVS_TYPE_INIT; 451 init->nvs_ver_min = nvs_ver; 452 init->nvs_ver_max = nvs_ver; 453 454 resp_len = sizeof(*resp); 455 resp = hn_nvs_xact_execute(sc, xact, init, sizeof(*init), &resp_len, 456 HN_NVS_TYPE_INIT_RESP); 457 if (resp == NULL) { 458 if_printf(sc->hn_ifp, "exec init failed\n"); 459 vmbus_xact_put(xact); 460 return (EIO); 461 } 462 463 status = resp->nvs_status; 464 vmbus_xact_put(xact); 465 466 if (status != HN_NVS_STATUS_OK) { 467 if (bootverbose) { 468 /* 469 * Caller may try another NVS version, and will log 470 * error if there are no more NVS versions to try, 471 * so don't bark out loud here. 472 */ 473 if_printf(sc->hn_ifp, "nvs init failed for ver 0x%x\n", 474 nvs_ver); 475 } 476 return (EINVAL); 477 } 478 return (0); 479} 480 481/* 482 * Configure MTU and enable VLAN. 483 */ 484static int 485hn_nvs_conf_ndis(struct hn_softc *sc, int mtu) 486{ 487 struct hn_nvs_ndis_conf conf; 488 int error; 489 490 memset(&conf, 0, sizeof(conf)); 491 conf.nvs_type = HN_NVS_TYPE_NDIS_CONF; 492 conf.nvs_mtu = mtu; 493 conf.nvs_caps = HN_NVS_NDIS_CONF_VLAN; 494 495 /* NOTE: No response. */ 496 error = hn_nvs_req_send(sc, &conf, sizeof(conf)); 497 if (error) { 498 if_printf(sc->hn_ifp, "send nvs ndis conf failed: %d\n", error); 499 return (error); 500 } 501 502 if (bootverbose) 503 if_printf(sc->hn_ifp, "nvs ndis conf done\n"); 504 sc->hn_caps |= HN_CAP_MTU | HN_CAP_VLAN; 505 return (0); 506} 507 508static int 509hn_nvs_init_ndis(struct hn_softc *sc) 510{ 511 struct hn_nvs_ndis_init ndis; 512 int error; 513 514 memset(&ndis, 0, sizeof(ndis)); 515 ndis.nvs_type = HN_NVS_TYPE_NDIS_INIT; 516 ndis.nvs_ndis_major = HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver); 517 ndis.nvs_ndis_minor = HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver); 518 519 /* NOTE: No response. */ 520 error = hn_nvs_req_send(sc, &ndis, sizeof(ndis)); 521 if (error) 522 if_printf(sc->hn_ifp, "send nvs ndis init failed: %d\n", error); 523 return (error); 524} 525 526static int 527hn_nvs_init(struct hn_softc *sc) 528{ 529 int i, error; 530 531 if (device_is_attached(sc->hn_dev)) { 532 /* 533 * NVS version and NDIS version MUST NOT be changed. 534 */ 535 if (bootverbose) { 536 if_printf(sc->hn_ifp, "reinit NVS version 0x%x, " 537 "NDIS version %u.%u\n", sc->hn_nvs_ver, 538 HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 539 HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 540 } 541 542 error = hn_nvs_doinit(sc, sc->hn_nvs_ver); 543 if (error) { 544 if_printf(sc->hn_ifp, "reinit NVS version 0x%x " 545 "failed: %d\n", sc->hn_nvs_ver, error); 546 } 547 return (error); 548 } 549 550 /* 551 * Find the supported NVS version and set NDIS version accordingly. 552 */ 553 for (i = 0; i < nitems(hn_nvs_version); ++i) { 554 error = hn_nvs_doinit(sc, hn_nvs_version[i]); 555 if (!error) { 556 sc->hn_nvs_ver = hn_nvs_version[i]; 557 558 /* Set NDIS version according to NVS version. */ 559 sc->hn_ndis_ver = HN_NDIS_VERSION_6_30; 560 if (sc->hn_nvs_ver <= HN_NVS_VERSION_4) 561 sc->hn_ndis_ver = HN_NDIS_VERSION_6_1; 562 563 if (bootverbose) { 564 if_printf(sc->hn_ifp, "NVS version 0x%x, " 565 "NDIS version %u.%u\n", sc->hn_nvs_ver, 566 HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), 567 HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); 568 } 569 return (0); 570 } 571 } 572 if_printf(sc->hn_ifp, "no NVS available\n"); 573 return (ENXIO); 574} 575 576int 577hn_nvs_attach(struct hn_softc *sc, int mtu) 578{ 579 int error; 580 581 /* 582 * Initialize NVS. 583 */ 584 error = hn_nvs_init(sc); 585 if (error) 586 return (error); 587 588 if (sc->hn_nvs_ver >= HN_NVS_VERSION_2) { 589 /* 590 * Configure NDIS before initializing it. 591 */ 592 error = hn_nvs_conf_ndis(sc, mtu); 593 if (error) 594 return (error); 595 } 596 597 /* 598 * Initialize NDIS. 599 */ 600 error = hn_nvs_init_ndis(sc); 601 if (error) 602 return (error); 603 604 /* 605 * Connect RXBUF. 606 */ 607 error = hn_nvs_conn_rxbuf(sc); 608 if (error) 609 return (error); 610 611 /* 612 * Connect chimney sending buffer. 613 */ 614 error = hn_nvs_conn_chim(sc); 615 if (error) 616 return (error); 617 return (0); 618} 619 620void 621hn_nvs_detach(struct hn_softc *sc) 622{ 623 624 /* NOTE: there are no requests to stop the NVS. */ 625 hn_nvs_disconn_rxbuf(sc); 626 hn_nvs_disconn_chim(sc); 627} 628 629void 630hn_nvs_sent_xact(struct hn_send_ctx *sndc, 631 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, 632 const void *data, int dlen) 633{ 634 635 vmbus_xact_wakeup(sndc->hn_cbarg, data, dlen); 636} 637 638static void 639hn_nvs_sent_none(struct hn_send_ctx *sndc __unused, 640 struct hn_softc *sc __unused, struct vmbus_channel *chan __unused, 641 const void *data __unused, int dlen __unused) 642{ 643 /* EMPTY */ 644} 645 646void 647hn_chim_free(struct hn_softc *sc, uint32_t chim_idx) 648{ 649 u_long mask; 650 uint32_t idx; 651 652 idx = chim_idx / LONG_BIT; 653 KASSERT(idx < sc->hn_chim_bmap_cnt, 654 ("invalid chimney index 0x%x", chim_idx)); 655 656 mask = 1UL << (chim_idx % LONG_BIT); 657 KASSERT(sc->hn_chim_bmap[idx] & mask, 658 ("index bitmap 0x%lx, chimney index %u, " 659 "bitmap idx %d, bitmask 0x%lx", 660 sc->hn_chim_bmap[idx], chim_idx, idx, mask)); 661 662 atomic_clear_long(&sc->hn_chim_bmap[idx], mask); 663} 664 665/* 666 * Net VSC on send 667 * Sends a packet on the specified Hyper-V device. 668 * Returns 0 on success, non-zero on failure. 669 */ 670int 671hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype, 672 struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt) 673{ 674 struct hn_nvs_rndis rndis; 675 int ret; 676 677 rndis.nvs_type = HN_NVS_TYPE_RNDIS; 678 rndis.nvs_rndis_mtype = rndis_mtype; 679 rndis.nvs_chim_idx = sndc->hn_chim_idx; 680 rndis.nvs_chim_sz = sndc->hn_chim_sz; 681 682 if (gpa_cnt) { 683 ret = hn_nvs_send_sglist(chan, gpa, gpa_cnt, 684 &rndis, sizeof(rndis), sndc); 685 } else { 686 ret = hn_nvs_send(chan, VMBUS_CHANPKT_FLAG_RC, 687 &rndis, sizeof(rndis), sndc); 688 } 689 690 return (ret); 691} 692 693int 694hn_nvs_alloc_subchans(struct hn_softc *sc, int *nsubch0) 695{ 696 struct vmbus_xact *xact; 697 struct hn_nvs_subch_req *req; 698 const struct hn_nvs_subch_resp *resp; 699 int error, nsubch_req; 700 uint32_t nsubch; 701 size_t resp_len; 702 703 nsubch_req = *nsubch0; 704 KASSERT(nsubch_req > 0, ("invalid # of sub-channels %d", nsubch_req)); 705 706 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req)); 707 if (xact == NULL) { 708 if_printf(sc->hn_ifp, "no xact for nvs subch alloc\n"); 709 return (ENXIO); 710 } 711 req = vmbus_xact_req_data(xact); 712 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ; 713 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC; 714 req->nvs_nsubch = nsubch_req; 715 716 resp_len = sizeof(*resp); 717 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len, 718 HN_NVS_TYPE_SUBCH_RESP); 719 if (resp == NULL) { 720 if_printf(sc->hn_ifp, "exec nvs subch alloc failed\n"); 721 error = EIO; 722 goto done; 723 } 724 if (resp->nvs_status != HN_NVS_STATUS_OK) { 725 if_printf(sc->hn_ifp, "nvs subch alloc failed: %x\n", 726 resp->nvs_status); 727 error = EIO; 728 goto done; 729 } 730 731 nsubch = resp->nvs_nsubch; 732 if (nsubch > nsubch_req) { 733 if_printf(sc->hn_ifp, "%u subchans are allocated, " 734 "requested %d\n", nsubch, nsubch_req); 735 nsubch = nsubch_req; 736 } 737 *nsubch0 = nsubch; 738 error = 0; 739done: 740 vmbus_xact_put(xact); 741 return (error); 742} 743