1 /*- 2 * Copyright (c) 2009-2012,2016 Microsoft Corp. 3 * Copyright (c) 2010-2012 Citrix Inc. 4 * Copyright (c) 2012 NetApp Inc. 5 * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice unmodified, this list of conditions, and the following 13 * disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * The OpenBSD port was done under funding by Esdenera Networks GmbH. 32 */ 33 34 #include "bpfilter.h" 35 #include "vlan.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/atomic.h> 40 #include <sys/device.h> 41 #include <sys/malloc.h> 42 #include <sys/mbuf.h> 43 #include <sys/queue.h> 44 #include <sys/sockio.h> 45 #include <sys/task.h> 46 47 #include <machine/bus.h> 48 49 #include <uvm/uvm_extern.h> 50 51 #include <dev/pv/hypervreg.h> 52 #include <dev/pv/hypervvar.h> 53 54 #include <dev/rndis.h> 55 #include <dev/pv/ndis.h> 56 #include <dev/pv/if_hvnreg.h> 57 58 #include <net/if.h> 59 #include <net/if_media.h> 60 61 #include <netinet/in.h> 62 #include <netinet/if_ether.h> 63 64 #if NBPFILTER > 0 65 #include <net/bpf.h> 66 #endif 67 68 #define HVN_NVS_MSGSIZE 32 69 #define HVN_NVS_BUFSIZE PAGE_SIZE 70 71 /* 72 * RNDIS control interface 73 */ 74 #define HVN_RNDIS_CTLREQS 4 75 #define HVN_RNDIS_BUFSIZE 512 76 77 struct rndis_cmd { 78 uint32_t rc_id; 79 struct hvn_nvs_rndis rc_msg; 80 void *rc_req; 81 bus_dmamap_t rc_dmap; 82 bus_dma_segment_t rc_segs; 83 int rc_nsegs; 84 uint64_t rc_gpa; 85 struct rndis_packet_msg rc_cmp; 86 uint32_t rc_cmplen; 87 uint8_t rc_cmpbuf[HVN_RNDIS_BUFSIZE]; 88 int rc_done; 89 TAILQ_ENTRY(rndis_cmd) rc_entry; 90 }; 91 TAILQ_HEAD(rndis_queue, rndis_cmd); 92 93 #define HVN_MAXMTU (9 * 1024) 94 95 #define HVN_RNDIS_XFER_SIZE 2048 96 97 /* 98 * Tx ring 99 */ 100 #define HVN_TX_DESC 256 101 #define HVN_TX_FRAGS 15 /* 31 is the max */ 102 #define HVN_TX_FRAG_SIZE PAGE_SIZE 103 #define HVN_TX_PKT_SIZE 16384 104 105 #define HVN_RNDIS_PKT_LEN \ 106 (sizeof(struct rndis_packet_msg) + \ 107 sizeof(struct rndis_pktinfo) + NDIS_VLAN_INFO_SIZE + \ 108 sizeof(struct rndis_pktinfo) + NDIS_TXCSUM_INFO_SIZE) 109 110 struct hvn_tx_desc { 111 uint32_t txd_id; 112 int txd_ready; 113 struct vmbus_gpa txd_sgl[HVN_TX_FRAGS + 1]; 114 int txd_nsge; 115 struct mbuf *txd_buf; 116 bus_dmamap_t txd_dmap; 117 struct vmbus_gpa txd_gpa; 118 struct rndis_packet_msg *txd_req; 119 }; 120 121 struct hvn_softc { 122 struct device sc_dev; 123 struct hv_softc *sc_hvsc; 124 struct hv_channel *sc_chan; 125 bus_dma_tag_t sc_dmat; 126 127 struct arpcom sc_ac; 128 struct ifmedia sc_media; 129 int sc_link_state; 130 131 /* NVS protocol */ 132 int sc_proto; 133 uint32_t sc_nvstid; 134 uint8_t sc_nvsrsp[HVN_NVS_MSGSIZE]; 135 uint8_t *sc_nvsbuf; 136 int sc_nvsdone; 137 138 /* RNDIS protocol */ 139 int sc_ndisver; 140 uint32_t sc_rndisrid; 141 struct rndis_queue sc_cntl_sq; /* submission queue */ 142 struct mutex sc_cntl_sqlck; 143 struct rndis_queue sc_cntl_cq; /* completion queue */ 144 struct mutex sc_cntl_cqlck; 145 struct rndis_queue sc_cntl_fq; /* free queue */ 146 struct mutex sc_cntl_fqlck; 147 struct rndis_cmd sc_cntl_msgs[HVN_RNDIS_CTLREQS]; 148 struct hvn_nvs_rndis sc_data_msg; 149 150 /* Rx ring */ 151 void *sc_rx_ring; 152 int sc_rx_size; 153 uint32_t sc_rx_hndl; 154 155 /* Tx ring */ 156 uint32_t sc_tx_next; 157 uint32_t sc_tx_avail; 158 struct hvn_tx_desc sc_tx_desc[HVN_TX_DESC]; 159 bus_dmamap_t sc_tx_rmap; 160 void *sc_tx_msgs; 161 bus_dma_segment_t sc_tx_mseg; 162 }; 163 164 int hvn_match(struct device *, void *, void *); 165 void hvn_attach(struct device *, struct device *, void *); 166 int hvn_ioctl(struct ifnet *, u_long, caddr_t); 167 int hvn_media_change(struct ifnet *); 168 void hvn_media_status(struct ifnet *, struct ifmediareq *); 169 int hvn_iff(struct hvn_softc *); 170 void hvn_init(struct hvn_softc *); 171 void hvn_stop(struct hvn_softc *); 172 void hvn_start(struct ifqueue *); 173 int hvn_encap(struct hvn_softc *, struct mbuf *, struct hvn_tx_desc **); 174 void hvn_decap(struct hvn_softc *, struct hvn_tx_desc *); 175 void hvn_txeof(struct hvn_softc *, uint64_t); 176 int hvn_rx_ring_create(struct hvn_softc *); 177 int hvn_rx_ring_destroy(struct hvn_softc *); 178 int hvn_tx_ring_create(struct hvn_softc *); 179 void hvn_tx_ring_destroy(struct hvn_softc *); 180 int hvn_set_capabilities(struct hvn_softc *); 181 int hvn_get_lladdr(struct hvn_softc *); 182 int hvn_set_lladdr(struct hvn_softc *); 183 void hvn_get_link_status(struct hvn_softc *); 184 void hvn_link_status(struct hvn_softc *); 185 186 /* NSVP */ 187 int hvn_nvs_attach(struct hvn_softc *); 188 void hvn_nvs_intr(void *); 189 int hvn_nvs_cmd(struct hvn_softc *, void *, size_t, uint64_t, int); 190 int hvn_nvs_ack(struct hvn_softc *, uint64_t); 191 void hvn_nvs_detach(struct hvn_softc *); 192 193 /* RNDIS */ 194 int hvn_rndis_attach(struct hvn_softc *); 195 int hvn_rndis_cmd(struct hvn_softc *, struct rndis_cmd *, int); 196 void hvn_rndis_input(struct hvn_softc *, uint64_t, void *); 197 void hvn_rxeof(struct hvn_softc *, caddr_t, uint32_t, struct mbuf_list *); 198 void hvn_rndis_complete(struct hvn_softc *, caddr_t, uint32_t); 199 int hvn_rndis_output(struct hvn_softc *, struct hvn_tx_desc *); 200 void hvn_rndis_status(struct hvn_softc *, caddr_t, uint32_t); 201 int hvn_rndis_query(struct hvn_softc *, uint32_t, void *, size_t *); 202 int hvn_rndis_set(struct hvn_softc *, uint32_t, void *, size_t); 203 int hvn_rndis_close(struct hvn_softc *); 204 void hvn_rndis_detach(struct hvn_softc *); 205 206 struct cfdriver hvn_cd = { 207 NULL, "hvn", DV_IFNET 208 }; 209 210 const struct cfattach hvn_ca = { 211 sizeof(struct hvn_softc), hvn_match, hvn_attach 212 }; 213 214 int 215 hvn_match(struct device *parent, void *match, void *aux) 216 { 217 struct hv_attach_args *aa = aux; 218 219 if (strcmp("network", aa->aa_ident)) 220 return (0); 221 222 return (1); 223 } 224 225 void 226 hvn_attach(struct device *parent, struct device *self, void *aux) 227 { 228 struct hv_attach_args *aa = aux; 229 struct hvn_softc *sc = (struct hvn_softc *)self; 230 struct ifnet *ifp = &sc->sc_ac.ac_if; 231 232 sc->sc_hvsc = (struct hv_softc *)parent; 233 sc->sc_chan = aa->aa_chan; 234 sc->sc_dmat = aa->aa_dmat; 235 236 strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 237 238 printf(" channel %u", sc->sc_chan->ch_id); 239 240 if (hvn_nvs_attach(sc)) { 241 printf(": failed to init NVSP\n"); 242 return; 243 } 244 245 if (hvn_rx_ring_create(sc)) { 246 printf(": failed to create Rx ring\n"); 247 goto detach; 248 } 249 250 if (hvn_tx_ring_create(sc)) { 251 printf(": failed to create Tx ring\n"); 252 goto detach; 253 } 254 255 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 256 ifp->if_xflags = IFXF_MPSAFE; 257 ifp->if_ioctl = hvn_ioctl; 258 ifp->if_qstart = hvn_start; 259 ifp->if_softc = sc; 260 261 ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | 262 IFCAP_CSUM_TCPv6; 263 if (sc->sc_ndisver > NDIS_VERSION_6_30) 264 ifp->if_capabilities |= IFCAP_CSUM_UDPv4 | IFCAP_CSUM_UDPv6; 265 266 if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) { 267 ifp->if_hardmtu = HVN_MAXMTU; 268 #if NVLAN > 0 269 ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 270 #endif 271 } 272 273 ifq_init_maxlen(&ifp->if_snd, HVN_TX_DESC - 1); 274 275 ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change, 276 hvn_media_status); 277 ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL); 278 ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL); 279 280 if_attach(ifp); 281 282 if (hvn_rndis_attach(sc)) { 283 printf(": failed to init RNDIS\n"); 284 goto detach; 285 } 286 287 printf(": NVS %d.%d NDIS %d.%d", sc->sc_proto >> 16, 288 sc->sc_proto & 0xffff, sc->sc_ndisver >> 16 , 289 sc->sc_ndisver & 0xffff); 290 291 if (hvn_set_capabilities(sc)) { 292 printf(": failed to setup offloading\n"); 293 hvn_rndis_detach(sc); 294 goto detach; 295 } 296 297 if (hvn_get_lladdr(sc)) { 298 printf(": failed to obtain an ethernet address\n"); 299 hvn_rndis_detach(sc); 300 goto detach; 301 } 302 303 printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); 304 305 ether_ifattach(ifp); 306 return; 307 308 detach: 309 hvn_rx_ring_destroy(sc); 310 hvn_tx_ring_destroy(sc); 311 hvn_nvs_detach(sc); 312 if (ifp->if_qstart) 313 if_detach(ifp); 314 } 315 316 int 317 hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 318 { 319 struct hvn_softc *sc = ifp->if_softc; 320 struct ifreq *ifr = (struct ifreq *)data; 321 int s, error = 0; 322 323 s = splnet(); 324 325 switch (command) { 326 case SIOCSIFADDR: 327 ifp->if_flags |= IFF_UP; 328 if (!(ifp->if_flags & IFF_RUNNING)) 329 hvn_init(sc); 330 break; 331 case SIOCSIFFLAGS: 332 if (ifp->if_flags & IFF_UP) { 333 if (ifp->if_flags & IFF_RUNNING) 334 error = ENETRESET; 335 else 336 hvn_init(sc); 337 } else { 338 if (ifp->if_flags & IFF_RUNNING) 339 hvn_stop(sc); 340 } 341 break; 342 case SIOCGIFMEDIA: 343 case SIOCSIFMEDIA: 344 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command); 345 break; 346 default: 347 error = ether_ioctl(ifp, &sc->sc_ac, command, data); 348 } 349 350 if (error == ENETRESET) { 351 if (ifp->if_flags & IFF_RUNNING) 352 hvn_iff(sc); 353 error = 0; 354 } 355 356 splx(s); 357 358 return (error); 359 } 360 361 int 362 hvn_media_change(struct ifnet *ifp) 363 { 364 return (0); 365 } 366 367 void 368 hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 369 { 370 struct hvn_softc *sc = ifp->if_softc; 371 372 hvn_get_link_status(sc); 373 hvn_link_status(sc); 374 375 ifmr->ifm_status = IFM_AVALID; 376 ifmr->ifm_active = IFM_ETHER | IFM_MANUAL; 377 if (sc->sc_link_state == LINK_STATE_UP) 378 ifmr->ifm_status |= IFM_ACTIVE; 379 } 380 381 void 382 hvn_link_status(struct hvn_softc *sc) 383 { 384 struct ifnet *ifp = &sc->sc_ac.ac_if; 385 386 if (sc->sc_link_state != ifp->if_link_state) { 387 ifp->if_link_state = sc->sc_link_state; 388 if_link_state_change(ifp); 389 } 390 } 391 392 int 393 hvn_iff(struct hvn_softc *sc) 394 { 395 struct ifnet *ifp = &sc->sc_ac.ac_if; 396 uint32_t filter = 0; 397 int rv; 398 399 ifp->if_flags &= ~IFF_ALLMULTI; 400 401 if ((ifp->if_flags & IFF_PROMISC) || sc->sc_ac.ac_multirangecnt > 0) { 402 ifp->if_flags |= IFF_ALLMULTI; 403 filter = NDIS_PACKET_TYPE_PROMISCUOUS; 404 } else { 405 filter = NDIS_PACKET_TYPE_BROADCAST | 406 NDIS_PACKET_TYPE_DIRECTED; 407 if (sc->sc_ac.ac_multicnt > 0) { 408 ifp->if_flags |= IFF_ALLMULTI; 409 filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; 410 } 411 } 412 413 rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER, 414 &filter, sizeof(filter)); 415 if (rv) 416 DPRINTF("%s: failed to set RNDIS filter to %#x\n", 417 sc->sc_dev.dv_xname, filter); 418 return (rv); 419 } 420 421 void 422 hvn_init(struct hvn_softc *sc) 423 { 424 struct ifnet *ifp = &sc->sc_ac.ac_if; 425 426 hvn_stop(sc); 427 428 if (hvn_iff(sc) == 0) { 429 ifp->if_flags |= IFF_RUNNING; 430 ifq_clr_oactive(&ifp->if_snd); 431 } 432 } 433 434 void 435 hvn_stop(struct hvn_softc *sc) 436 { 437 struct ifnet *ifp = &sc->sc_ac.ac_if; 438 439 if (ifp->if_flags & IFF_RUNNING) { 440 ifp->if_flags &= ~IFF_RUNNING; 441 hvn_rndis_close(sc); 442 } 443 444 ifq_barrier(&ifp->if_snd); 445 sched_barrier(NULL); 446 447 ifq_clr_oactive(&ifp->if_snd); 448 } 449 450 void 451 hvn_start(struct ifqueue *ifq) 452 { 453 struct ifnet *ifp = ifq->ifq_if; 454 struct hvn_softc *sc = ifp->if_softc; 455 struct hvn_tx_desc *txd; 456 struct mbuf *m; 457 458 for (;;) { 459 if (!sc->sc_tx_avail) { 460 /* transient */ 461 ifq_set_oactive(ifq); 462 break; 463 } 464 465 m = ifq_dequeue(ifq); 466 if (m == NULL) 467 break; 468 469 if (hvn_encap(sc, m, &txd)) { 470 /* the chain is too large */ 471 ifp->if_oerrors++; 472 m_freem(m); 473 continue; 474 } 475 476 #if NBPFILTER > 0 477 if (ifp->if_bpf) 478 bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); 479 #endif 480 481 if (hvn_rndis_output(sc, txd)) { 482 hvn_decap(sc, txd); 483 ifp->if_oerrors++; 484 m_freem(m); 485 continue; 486 } 487 488 sc->sc_tx_next++; 489 } 490 } 491 492 static inline char * 493 hvn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize, 494 size_t datalen, uint32_t type) 495 { 496 struct rndis_pktinfo *pi; 497 size_t pi_size = sizeof(*pi) + datalen; 498 char *cp; 499 500 KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= 501 pktsize); 502 503 cp = (char *)pkt + pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 504 pi = (struct rndis_pktinfo *)cp; 505 pi->rm_size = pi_size; 506 pi->rm_type = type; 507 pi->rm_pktinfooffset = sizeof(*pi); 508 pkt->rm_pktinfolen += pi_size; 509 pkt->rm_dataoffset += pi_size; 510 pkt->rm_len += pi_size; 511 return ((char *)pi->rm_data); 512 } 513 514 int 515 hvn_encap(struct hvn_softc *sc, struct mbuf *m, struct hvn_tx_desc **txd0) 516 { 517 struct hvn_tx_desc *txd; 518 struct rndis_packet_msg *pkt; 519 bus_dma_segment_t *seg; 520 size_t pktlen; 521 int i, rv; 522 523 do { 524 txd = &sc->sc_tx_desc[sc->sc_tx_next % HVN_TX_DESC]; 525 sc->sc_tx_next++; 526 } while (!txd->txd_ready); 527 txd->txd_ready = 0; 528 529 pkt = txd->txd_req; 530 memset(pkt, 0, HVN_RNDIS_PKT_LEN); 531 pkt->rm_type = REMOTE_NDIS_PACKET_MSG; 532 pkt->rm_len = sizeof(*pkt) + m->m_pkthdr.len; 533 pkt->rm_dataoffset = RNDIS_DATA_OFFSET; 534 pkt->rm_datalen = m->m_pkthdr.len; 535 pkt->rm_pktinfooffset = sizeof(*pkt); /* adjusted below */ 536 pkt->rm_pktinfolen = 0; 537 538 rv = bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m, BUS_DMA_READ | 539 BUS_DMA_NOWAIT); 540 switch (rv) { 541 case 0: 542 break; 543 case EFBIG: 544 if (m_defrag(m, M_NOWAIT) == 0 && 545 bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m, 546 BUS_DMA_READ | BUS_DMA_NOWAIT) == 0) 547 break; 548 /* FALLTHROUGH */ 549 default: 550 DPRINTF("%s: failed to load mbuf\n", sc->sc_dev.dv_xname); 551 return (-1); 552 } 553 txd->txd_buf = m; 554 555 #if NVLAN > 0 556 if (m->m_flags & M_VLANTAG) { 557 uint32_t vlan; 558 char *cp; 559 560 vlan = NDIS_VLAN_INFO(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag), 561 EVL_PRIOFTAG(m->m_pkthdr.ether_vtag)); 562 cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN, 563 NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN); 564 memcpy(cp, &vlan, NDIS_VLAN_INFO_SIZE); 565 } 566 #endif 567 568 if (m->m_pkthdr.csum_flags & (M_IPV4_CSUM_OUT | M_UDP_CSUM_OUT | 569 M_TCP_CSUM_OUT)) { 570 uint32_t csum = NDIS_TXCSUM_INFO_IPV4; 571 char *cp; 572 573 if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) 574 csum |= NDIS_TXCSUM_INFO_IPCS; 575 if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) 576 csum |= NDIS_TXCSUM_INFO_TCPCS; 577 if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) 578 csum |= NDIS_TXCSUM_INFO_UDPCS; 579 cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN, 580 NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM); 581 memcpy(cp, &csum, NDIS_TXCSUM_INFO_SIZE); 582 } 583 584 pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen; 585 pkt->rm_pktinfooffset -= RNDIS_HEADER_OFFSET; 586 587 /* Attach an RNDIS message to the first slot */ 588 txd->txd_sgl[0].gpa_page = txd->txd_gpa.gpa_page; 589 txd->txd_sgl[0].gpa_ofs = txd->txd_gpa.gpa_ofs; 590 txd->txd_sgl[0].gpa_len = pktlen; 591 txd->txd_nsge = txd->txd_dmap->dm_nsegs + 1; 592 593 for (i = 0; i < txd->txd_dmap->dm_nsegs; i++) { 594 seg = &txd->txd_dmap->dm_segs[i]; 595 txd->txd_sgl[1 + i].gpa_page = atop(seg->ds_addr); 596 txd->txd_sgl[1 + i].gpa_ofs = seg->ds_addr & PAGE_MASK; 597 txd->txd_sgl[1 + i].gpa_len = seg->ds_len; 598 } 599 600 *txd0 = txd; 601 602 atomic_dec_int(&sc->sc_tx_avail); 603 604 return (0); 605 } 606 607 void 608 hvn_decap(struct hvn_softc *sc, struct hvn_tx_desc *txd) 609 { 610 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0, 611 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 612 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap); 613 txd->txd_buf = NULL; 614 txd->txd_nsge = 0; 615 txd->txd_ready = 1; 616 atomic_inc_int(&sc->sc_tx_avail); 617 } 618 619 void 620 hvn_txeof(struct hvn_softc *sc, uint64_t tid) 621 { 622 struct hvn_tx_desc *txd; 623 struct mbuf *m; 624 uint32_t id = tid >> 32; 625 626 if ((tid & 0xffffffffU) != 0) 627 return; 628 id -= HVN_NVS_CHIM_SIG; 629 if (id >= HVN_TX_DESC) 630 panic("tx packet index too large: %u", id); 631 632 txd = &sc->sc_tx_desc[id]; 633 634 if ((m = txd->txd_buf) == NULL) 635 panic("%s: no mbuf @%u", sc->sc_dev.dv_xname, id); 636 txd->txd_buf = NULL; 637 638 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0, 639 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 640 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap); 641 m_freem(m); 642 643 txd->txd_ready = 1; 644 645 atomic_inc_int(&sc->sc_tx_avail); 646 647 } 648 649 int 650 hvn_rx_ring_create(struct hvn_softc *sc) 651 { 652 struct hvn_nvs_rxbuf_conn cmd; 653 struct hvn_nvs_rxbuf_conn_resp *rsp; 654 uint64_t tid; 655 656 if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_2) 657 sc->sc_rx_size = 15 * 1024 * 1024; /* 15MB */ 658 else 659 sc->sc_rx_size = 16 * 1024 * 1024; /* 16MB */ 660 sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero, 661 cold ? &kd_nowait : &kd_waitok); 662 if (sc->sc_rx_ring == NULL) { 663 DPRINTF("%s: failed to allocate Rx ring buffer\n", 664 sc->sc_dev.dv_xname); 665 return (-1); 666 } 667 if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size, 668 &sc->sc_rx_hndl)) { 669 DPRINTF("%s: failed to obtain a PA handle\n", 670 sc->sc_dev.dv_xname); 671 goto errout; 672 } 673 674 memset(&cmd, 0, sizeof(cmd)); 675 cmd.nvs_type = HVN_NVS_TYPE_RXBUF_CONN; 676 cmd.nvs_gpadl = sc->sc_rx_hndl; 677 cmd.nvs_sig = HVN_NVS_RXBUF_SIG; 678 679 tid = atomic_inc_int_nv(&sc->sc_nvstid); 680 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100)) 681 goto errout; 682 683 rsp = (struct hvn_nvs_rxbuf_conn_resp *)&sc->sc_nvsrsp; 684 if (rsp->nvs_status != HVN_NVS_STATUS_OK) { 685 DPRINTF("%s: failed to set up the Rx ring\n", 686 sc->sc_dev.dv_xname); 687 goto errout; 688 } 689 if (rsp->nvs_nsect > 1) { 690 DPRINTF("%s: invalid number of Rx ring sections: %u\n", 691 sc->sc_dev.dv_xname, rsp->nvs_nsect); 692 hvn_rx_ring_destroy(sc); 693 return (-1); 694 } 695 return (0); 696 697 errout: 698 if (sc->sc_rx_hndl) { 699 hv_handle_free(sc->sc_chan, sc->sc_rx_hndl); 700 sc->sc_rx_hndl = 0; 701 } 702 if (sc->sc_rx_ring) { 703 km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero); 704 sc->sc_rx_ring = NULL; 705 } 706 return (-1); 707 } 708 709 int 710 hvn_rx_ring_destroy(struct hvn_softc *sc) 711 { 712 struct hvn_nvs_rxbuf_disconn cmd; 713 uint64_t tid; 714 715 if (sc->sc_rx_ring == NULL) 716 return (0); 717 718 memset(&cmd, 0, sizeof(cmd)); 719 cmd.nvs_type = HVN_NVS_TYPE_RXBUF_DISCONN; 720 cmd.nvs_sig = HVN_NVS_RXBUF_SIG; 721 722 tid = atomic_inc_int_nv(&sc->sc_nvstid); 723 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0)) 724 return (-1); 725 726 delay(100); 727 728 hv_handle_free(sc->sc_chan, sc->sc_rx_hndl); 729 730 sc->sc_rx_hndl = 0; 731 732 km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero); 733 sc->sc_rx_ring = NULL; 734 735 return (0); 736 } 737 738 int 739 hvn_tx_ring_create(struct hvn_softc *sc) 740 { 741 struct hvn_tx_desc *txd; 742 bus_dma_segment_t *seg; 743 size_t msgsize; 744 int i, rsegs; 745 paddr_t pa; 746 747 msgsize = roundup(HVN_RNDIS_PKT_LEN, 128); 748 749 /* Allocate memory to store RNDIS messages */ 750 if (bus_dmamem_alloc(sc->sc_dmat, msgsize * HVN_TX_DESC, PAGE_SIZE, 0, 751 &sc->sc_tx_mseg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_WAITOK)) { 752 DPRINTF("%s: failed to allocate memory for RDNIS messages\n", 753 sc->sc_dev.dv_xname); 754 goto errout; 755 } 756 if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tx_mseg, 1, msgsize * 757 HVN_TX_DESC, (caddr_t *)&sc->sc_tx_msgs, BUS_DMA_WAITOK)) { 758 DPRINTF("%s: failed to establish mapping for RDNIS messages\n", 759 sc->sc_dev.dv_xname); 760 goto errout; 761 } 762 if (bus_dmamap_create(sc->sc_dmat, msgsize * HVN_TX_DESC, 1, 763 msgsize * HVN_TX_DESC, 0, BUS_DMA_WAITOK, &sc->sc_tx_rmap)) { 764 DPRINTF("%s: failed to create map for RDNIS messages\n", 765 sc->sc_dev.dv_xname); 766 goto errout; 767 } 768 if (bus_dmamap_load(sc->sc_dmat, sc->sc_tx_rmap, sc->sc_tx_msgs, 769 msgsize * HVN_TX_DESC, NULL, BUS_DMA_WAITOK)) { 770 DPRINTF("%s: failed to create map for RDNIS messages\n", 771 sc->sc_dev.dv_xname); 772 goto errout; 773 } 774 775 for (i = 0; i < HVN_TX_DESC; i++) { 776 txd = &sc->sc_tx_desc[i]; 777 if (bus_dmamap_create(sc->sc_dmat, HVN_TX_PKT_SIZE, 778 HVN_TX_FRAGS, HVN_TX_FRAG_SIZE, PAGE_SIZE, 779 BUS_DMA_WAITOK, &txd->txd_dmap)) { 780 DPRINTF("%s: failed to create map for TX descriptors\n", 781 sc->sc_dev.dv_xname); 782 goto errout; 783 } 784 seg = &sc->sc_tx_rmap->dm_segs[0]; 785 pa = seg->ds_addr + (msgsize * i); 786 txd->txd_gpa.gpa_page = atop(pa); 787 txd->txd_gpa.gpa_ofs = pa & PAGE_MASK; 788 txd->txd_gpa.gpa_len = msgsize; 789 txd->txd_req = (void *)((caddr_t)sc->sc_tx_msgs + 790 (msgsize * i)); 791 txd->txd_id = i + HVN_NVS_CHIM_SIG; 792 txd->txd_ready = 1; 793 } 794 sc->sc_tx_avail = HVN_TX_DESC; 795 796 return (0); 797 798 errout: 799 hvn_tx_ring_destroy(sc); 800 return (-1); 801 } 802 803 void 804 hvn_tx_ring_destroy(struct hvn_softc *sc) 805 { 806 struct hvn_tx_desc *txd; 807 int i; 808 809 for (i = 0; i < HVN_TX_DESC; i++) { 810 txd = &sc->sc_tx_desc[i]; 811 if (txd->txd_dmap == NULL) 812 continue; 813 bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0, 814 BUS_DMASYNC_POSTWRITE); 815 bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap); 816 bus_dmamap_destroy(sc->sc_dmat, txd->txd_dmap); 817 txd->txd_dmap = NULL; 818 if (txd->txd_buf == NULL) 819 continue; 820 m_free(txd->txd_buf); 821 txd->txd_buf = NULL; 822 } 823 if (sc->sc_tx_rmap) { 824 bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0, 825 BUS_DMASYNC_POSTWRITE); 826 bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap); 827 bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap); 828 } 829 if (sc->sc_tx_msgs) { 830 size_t msgsize = roundup(HVN_RNDIS_PKT_LEN, 128); 831 832 bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_msgs, 833 msgsize * HVN_TX_DESC); 834 bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_mseg, 1); 835 } 836 sc->sc_tx_rmap = NULL; 837 sc->sc_tx_msgs = NULL; 838 } 839 840 int 841 hvn_get_lladdr(struct hvn_softc *sc) 842 { 843 char enaddr[ETHER_ADDR_LEN]; 844 size_t addrlen = ETHER_ADDR_LEN; 845 int rv; 846 847 rv = hvn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, 848 enaddr, &addrlen); 849 if (rv == 0 && addrlen == ETHER_ADDR_LEN) 850 memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN); 851 return (rv); 852 } 853 854 int 855 hvn_set_lladdr(struct hvn_softc *sc) 856 { 857 return (hvn_rndis_set(sc, OID_802_3_CURRENT_ADDRESS, 858 sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN)); 859 } 860 861 void 862 hvn_get_link_status(struct hvn_softc *sc) 863 { 864 uint32_t state; 865 size_t len = sizeof(state); 866 867 if (hvn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, 868 &state, &len) == 0) 869 sc->sc_link_state = (state == NDIS_MEDIA_STATE_CONNECTED) ? 870 LINK_STATE_UP : LINK_STATE_DOWN; 871 } 872 873 int 874 hvn_nvs_attach(struct hvn_softc *sc) 875 { 876 const uint32_t protos[] = { 877 HVN_NVS_PROTO_VERSION_5, HVN_NVS_PROTO_VERSION_4, 878 HVN_NVS_PROTO_VERSION_2, HVN_NVS_PROTO_VERSION_1 879 }; 880 struct hvn_nvs_init cmd; 881 struct hvn_nvs_init_resp *rsp; 882 struct hvn_nvs_ndis_init ncmd; 883 struct hvn_nvs_ndis_conf ccmd; 884 uint32_t ndisver, ringsize; 885 uint64_t tid; 886 int i; 887 888 sc->sc_nvsbuf = malloc(HVN_NVS_BUFSIZE, M_DEVBUF, M_ZERO | 889 (cold ? M_NOWAIT : M_WAITOK)); 890 if (sc->sc_nvsbuf == NULL) { 891 DPRINTF("%s: failed to allocate channel data buffer\n", 892 sc->sc_dev.dv_xname); 893 return (-1); 894 } 895 896 /* We need to be able to fit all RNDIS control and data messages */ 897 ringsize = HVN_RNDIS_CTLREQS * 898 (sizeof(struct hvn_nvs_rndis) + sizeof(struct vmbus_gpa)) + 899 HVN_TX_DESC * (sizeof(struct hvn_nvs_rndis) + 900 (HVN_TX_FRAGS + 1) * sizeof(struct vmbus_gpa)); 901 902 sc->sc_chan->ch_flags &= ~CHF_BATCHED; 903 904 /* Associate our interrupt handler with the channel */ 905 if (hv_channel_open(sc->sc_chan, ringsize, NULL, 0, 906 hvn_nvs_intr, sc)) { 907 DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname); 908 free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE); 909 return (-1); 910 } 911 912 hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname); 913 914 memset(&cmd, 0, sizeof(cmd)); 915 cmd.nvs_type = HVN_NVS_TYPE_INIT; 916 for (i = 0; i < nitems(protos); i++) { 917 cmd.nvs_ver_min = cmd.nvs_ver_max = protos[i]; 918 tid = atomic_inc_int_nv(&sc->sc_nvstid); 919 if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100)) 920 return (-1); 921 rsp = (struct hvn_nvs_init_resp *)&sc->sc_nvsrsp; 922 if (rsp->nvs_status == HVN_NVS_STATUS_OK) { 923 sc->sc_proto = protos[i]; 924 break; 925 } 926 } 927 if (!sc->sc_proto) { 928 DPRINTF("%s: failed to negotiate NVSP version\n", 929 sc->sc_dev.dv_xname); 930 return (-1); 931 } 932 933 if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) { 934 memset(&ccmd, 0, sizeof(ccmd)); 935 ccmd.nvs_type = HVN_NVS_TYPE_NDIS_CONF; 936 ccmd.nvs_mtu = HVN_MAXMTU; 937 ccmd.nvs_caps = HVN_NVS_NDIS_CONF_VLAN; 938 939 tid = atomic_inc_int_nv(&sc->sc_nvstid); 940 if (hvn_nvs_cmd(sc, &ccmd, sizeof(ccmd), tid, 100)) 941 return (-1); 942 } 943 944 memset(&ncmd, 0, sizeof(ncmd)); 945 ncmd.nvs_type = HVN_NVS_TYPE_NDIS_INIT; 946 if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_4) 947 ndisver = NDIS_VERSION_6_1; 948 else 949 ndisver = NDIS_VERSION_6_30; 950 ncmd.nvs_ndis_major = (ndisver & 0xffff0000) >> 16; 951 ncmd.nvs_ndis_minor = (ndisver & 0x0000ffff); 952 953 tid = atomic_inc_int_nv(&sc->sc_nvstid); 954 if (hvn_nvs_cmd(sc, &ncmd, sizeof(ncmd), tid, 100)) 955 return (-1); 956 957 sc->sc_ndisver = ndisver; 958 959 return (0); 960 } 961 962 void 963 hvn_nvs_intr(void *arg) 964 { 965 struct hvn_softc *sc = arg; 966 struct ifnet *ifp = &sc->sc_ac.ac_if; 967 struct vmbus_chanpkt_hdr *cph; 968 struct hvn_nvs_hdr *nvs; 969 uint64_t rid; 970 uint32_t rlen; 971 int rv; 972 973 for (;;) { 974 rv = hv_channel_recv(sc->sc_chan, sc->sc_nvsbuf, 975 HVN_NVS_BUFSIZE, &rlen, &rid, 1); 976 if (rv != 0 || rlen == 0) { 977 if (rv != EAGAIN) 978 printf("%s: failed to receive an NVSP " 979 "packet\n", sc->sc_dev.dv_xname); 980 break; 981 } 982 cph = (struct vmbus_chanpkt_hdr *)sc->sc_nvsbuf; 983 nvs = (struct hvn_nvs_hdr *)VMBUS_CHANPKT_CONST_DATA(cph); 984 985 if (cph->cph_type == VMBUS_CHANPKT_TYPE_COMP) { 986 switch (nvs->nvs_type) { 987 case HVN_NVS_TYPE_INIT_RESP: 988 case HVN_NVS_TYPE_RXBUF_CONNRESP: 989 case HVN_NVS_TYPE_CHIM_CONNRESP: 990 case HVN_NVS_TYPE_SUBCH_RESP: 991 /* copy the response back */ 992 memcpy(&sc->sc_nvsrsp, nvs, HVN_NVS_MSGSIZE); 993 sc->sc_nvsdone = 1; 994 wakeup_one(&sc->sc_nvsrsp); 995 break; 996 case HVN_NVS_TYPE_RNDIS_ACK: 997 hvn_txeof(sc, cph->cph_tid); 998 break; 999 default: 1000 printf("%s: unhandled NVSP packet type %u " 1001 "on completion\n", sc->sc_dev.dv_xname, 1002 nvs->nvs_type); 1003 } 1004 } else if (cph->cph_type == VMBUS_CHANPKT_TYPE_RXBUF) { 1005 switch (nvs->nvs_type) { 1006 case HVN_NVS_TYPE_RNDIS: 1007 hvn_rndis_input(sc, cph->cph_tid, cph); 1008 break; 1009 default: 1010 printf("%s: unhandled NVSP packet type %u " 1011 "on receive\n", sc->sc_dev.dv_xname, 1012 nvs->nvs_type); 1013 } 1014 } else 1015 printf("%s: unknown NVSP packet type %u\n", 1016 sc->sc_dev.dv_xname, cph->cph_type); 1017 } 1018 1019 if (ifq_is_oactive(&ifp->if_snd)) 1020 ifq_restart(&ifp->if_snd); 1021 } 1022 1023 int 1024 hvn_nvs_cmd(struct hvn_softc *sc, void *cmd, size_t cmdsize, uint64_t tid, 1025 int timo) 1026 { 1027 struct hvn_nvs_hdr *hdr = cmd; 1028 int tries = 10; 1029 int rv, s; 1030 1031 KERNEL_ASSERT_LOCKED(); 1032 1033 sc->sc_nvsdone = 0; 1034 1035 do { 1036 rv = hv_channel_send(sc->sc_chan, cmd, cmdsize, 1037 tid, VMBUS_CHANPKT_TYPE_INBAND, 1038 timo ? VMBUS_CHANPKT_FLAG_RC : 0); 1039 if (rv == EAGAIN) { 1040 if (cold) 1041 delay(1000); 1042 else { 1043 tsleep_nsec(cmd, PRIBIO, "nvsout", 1044 USEC_TO_NSEC(1000)); 1045 } 1046 } else if (rv) { 1047 DPRINTF("%s: NVSP operation %u send error %d\n", 1048 sc->sc_dev.dv_xname, hdr->nvs_type, rv); 1049 return (rv); 1050 } 1051 } while (rv != 0 && --tries > 0); 1052 1053 if (tries == 0 && rv != 0) { 1054 printf("%s: NVSP operation %u send error %d\n", 1055 sc->sc_dev.dv_xname, hdr->nvs_type, rv); 1056 return (rv); 1057 } 1058 1059 if (timo == 0) 1060 return (0); 1061 1062 do { 1063 if (cold) 1064 delay(1000); 1065 else { 1066 tsleep_nsec(sc, PRIBIO | PCATCH, "nvscmd", 1067 USEC_TO_NSEC(1000)); 1068 } 1069 s = splnet(); 1070 hvn_nvs_intr(sc); 1071 splx(s); 1072 } while (--timo > 0 && sc->sc_nvsdone != 1); 1073 1074 if (timo == 0 && sc->sc_nvsdone != 1) { 1075 printf("%s: NVSP operation %u timed out\n", 1076 sc->sc_dev.dv_xname, hdr->nvs_type); 1077 return (ETIMEDOUT); 1078 } 1079 return (0); 1080 } 1081 1082 int 1083 hvn_nvs_ack(struct hvn_softc *sc, uint64_t tid) 1084 { 1085 struct hvn_nvs_rndis_ack cmd; 1086 int tries = 5; 1087 int rv; 1088 1089 cmd.nvs_type = HVN_NVS_TYPE_RNDIS_ACK; 1090 cmd.nvs_status = HVN_NVS_STATUS_OK; 1091 do { 1092 rv = hv_channel_send(sc->sc_chan, &cmd, sizeof(cmd), 1093 tid, VMBUS_CHANPKT_TYPE_COMP, 0); 1094 if (rv == EAGAIN) 1095 delay(10); 1096 else if (rv) { 1097 DPRINTF("%s: NVSP acknowledgement error %d\n", 1098 sc->sc_dev.dv_xname, rv); 1099 return (rv); 1100 } 1101 } while (rv != 0 && --tries > 0); 1102 return (rv); 1103 } 1104 1105 void 1106 hvn_nvs_detach(struct hvn_softc *sc) 1107 { 1108 if (hv_channel_close(sc->sc_chan) == 0) { 1109 free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE); 1110 sc->sc_nvsbuf = NULL; 1111 } 1112 } 1113 1114 static inline struct rndis_cmd * 1115 hvn_alloc_cmd(struct hvn_softc *sc) 1116 { 1117 struct rndis_cmd *rc; 1118 1119 mtx_enter(&sc->sc_cntl_fqlck); 1120 while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL) 1121 msleep_nsec(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck, 1122 PRIBIO, "nvsalloc", INFSLP); 1123 TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry); 1124 mtx_leave(&sc->sc_cntl_fqlck); 1125 return (rc); 1126 } 1127 1128 static inline void 1129 hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc) 1130 { 1131 mtx_enter(&sc->sc_cntl_sqlck); 1132 TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry); 1133 mtx_leave(&sc->sc_cntl_sqlck); 1134 } 1135 1136 static inline struct rndis_cmd * 1137 hvn_complete_cmd(struct hvn_softc *sc, uint32_t id) 1138 { 1139 struct rndis_cmd *rc; 1140 1141 mtx_enter(&sc->sc_cntl_sqlck); 1142 TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) { 1143 if (rc->rc_id == id) { 1144 TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry); 1145 break; 1146 } 1147 } 1148 mtx_leave(&sc->sc_cntl_sqlck); 1149 if (rc != NULL) { 1150 mtx_enter(&sc->sc_cntl_cqlck); 1151 TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry); 1152 mtx_leave(&sc->sc_cntl_cqlck); 1153 } 1154 return (rc); 1155 } 1156 1157 static inline void 1158 hvn_release_cmd(struct hvn_softc *sc, struct rndis_cmd *rc) 1159 { 1160 mtx_enter(&sc->sc_cntl_cqlck); 1161 TAILQ_REMOVE(&sc->sc_cntl_cq, rc, rc_entry); 1162 mtx_leave(&sc->sc_cntl_cqlck); 1163 } 1164 1165 static inline int 1166 hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc) 1167 { 1168 struct rndis_cmd *rn; 1169 1170 mtx_enter(&sc->sc_cntl_sqlck); 1171 TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) { 1172 if (rn == rc) { 1173 TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry); 1174 mtx_leave(&sc->sc_cntl_sqlck); 1175 return (0); 1176 } 1177 } 1178 mtx_leave(&sc->sc_cntl_sqlck); 1179 return (-1); 1180 } 1181 1182 static inline void 1183 hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc) 1184 { 1185 memset(rc->rc_req, 0, sizeof(struct rndis_packet_msg)); 1186 memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp)); 1187 memset(&rc->rc_msg, 0, sizeof(rc->rc_msg)); 1188 mtx_enter(&sc->sc_cntl_fqlck); 1189 TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry); 1190 mtx_leave(&sc->sc_cntl_fqlck); 1191 wakeup(&sc->sc_cntl_fq); 1192 } 1193 1194 int 1195 hvn_rndis_attach(struct hvn_softc *sc) 1196 { 1197 struct rndis_init_req *req; 1198 struct rndis_init_comp *cmp; 1199 struct rndis_cmd *rc; 1200 int i, rv; 1201 1202 /* RNDIS control message queues */ 1203 TAILQ_INIT(&sc->sc_cntl_sq); 1204 TAILQ_INIT(&sc->sc_cntl_cq); 1205 TAILQ_INIT(&sc->sc_cntl_fq); 1206 mtx_init(&sc->sc_cntl_sqlck, IPL_NET); 1207 mtx_init(&sc->sc_cntl_cqlck, IPL_NET); 1208 mtx_init(&sc->sc_cntl_fqlck, IPL_NET); 1209 1210 for (i = 0; i < HVN_RNDIS_CTLREQS; i++) { 1211 rc = &sc->sc_cntl_msgs[i]; 1212 if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, 1213 PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) { 1214 DPRINTF("%s: failed to create RNDIS command map\n", 1215 sc->sc_dev.dv_xname); 1216 goto errout; 1217 } 1218 if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 1219 0, &rc->rc_segs, 1, &rc->rc_nsegs, BUS_DMA_NOWAIT | 1220 BUS_DMA_ZERO)) { 1221 DPRINTF("%s: failed to allocate RNDIS command\n", 1222 sc->sc_dev.dv_xname); 1223 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap); 1224 goto errout; 1225 } 1226 if (bus_dmamem_map(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs, 1227 PAGE_SIZE, (caddr_t *)&rc->rc_req, BUS_DMA_NOWAIT)) { 1228 DPRINTF("%s: failed to allocate RNDIS command\n", 1229 sc->sc_dev.dv_xname); 1230 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, 1231 rc->rc_nsegs); 1232 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap); 1233 goto errout; 1234 } 1235 if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req, 1236 PAGE_SIZE, NULL, BUS_DMA_WAITOK)) { 1237 DPRINTF("%s: failed to load RNDIS command map\n", 1238 sc->sc_dev.dv_xname); 1239 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, 1240 rc->rc_nsegs); 1241 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap); 1242 goto errout; 1243 } 1244 rc->rc_gpa = atop(rc->rc_dmap->dm_segs[0].ds_addr); 1245 TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry); 1246 } 1247 1248 rc = hvn_alloc_cmd(sc); 1249 1250 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1251 BUS_DMASYNC_PREREAD); 1252 1253 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid); 1254 1255 req = rc->rc_req; 1256 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG; 1257 req->rm_len = sizeof(*req); 1258 req->rm_rid = rc->rc_id; 1259 req->rm_ver_major = RNDIS_VERSION_MAJOR; 1260 req->rm_ver_minor = RNDIS_VERSION_MINOR; 1261 req->rm_max_xfersz = HVN_RNDIS_XFER_SIZE; 1262 1263 rc->rc_cmplen = sizeof(*cmp); 1264 1265 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1266 BUS_DMASYNC_PREWRITE); 1267 1268 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) { 1269 DPRINTF("%s: INITIALIZE_MSG failed, error %d\n", 1270 sc->sc_dev.dv_xname, rv); 1271 hvn_free_cmd(sc, rc); 1272 goto errout; 1273 } 1274 cmp = (struct rndis_init_comp *)&rc->rc_cmp; 1275 if (cmp->rm_status != RNDIS_STATUS_SUCCESS) { 1276 DPRINTF("%s: failed to init RNDIS, error %#x\n", 1277 sc->sc_dev.dv_xname, cmp->rm_status); 1278 hvn_free_cmd(sc, rc); 1279 goto errout; 1280 } 1281 1282 hvn_free_cmd(sc, rc); 1283 1284 /* Initialize RNDIS Data command */ 1285 memset(&sc->sc_data_msg, 0, sizeof(sc->sc_data_msg)); 1286 sc->sc_data_msg.nvs_type = HVN_NVS_TYPE_RNDIS; 1287 sc->sc_data_msg.nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_DATA; 1288 sc->sc_data_msg.nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID; 1289 1290 return (0); 1291 1292 errout: 1293 for (i = 0; i < HVN_RNDIS_CTLREQS; i++) { 1294 rc = &sc->sc_cntl_msgs[i]; 1295 if (rc->rc_req == NULL) 1296 continue; 1297 TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry); 1298 bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs); 1299 rc->rc_req = NULL; 1300 bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap); 1301 } 1302 return (-1); 1303 } 1304 1305 int 1306 hvn_set_capabilities(struct hvn_softc *sc) 1307 { 1308 struct ndis_offload_params params; 1309 size_t len = sizeof(params); 1310 1311 memset(¶ms, 0, sizeof(params)); 1312 1313 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT; 1314 if (sc->sc_ndisver < NDIS_VERSION_6_30) { 1315 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2; 1316 len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1; 1317 } else { 1318 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3; 1319 len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE; 1320 } 1321 1322 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX; 1323 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX; 1324 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX; 1325 if (sc->sc_ndisver >= NDIS_VERSION_6_30) { 1326 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX; 1327 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX; 1328 } 1329 1330 return (hvn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, len)); 1331 } 1332 1333 int 1334 hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo) 1335 { 1336 struct hvn_nvs_rndis *msg = &rc->rc_msg; 1337 struct rndis_msghdr *hdr = rc->rc_req; 1338 struct vmbus_gpa sgl[1]; 1339 int tries = 10; 1340 int rv, s; 1341 1342 KERNEL_ASSERT_LOCKED(); 1343 1344 KASSERT(timo > 0); 1345 1346 msg->nvs_type = HVN_NVS_TYPE_RNDIS; 1347 msg->nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_CTRL; 1348 msg->nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID; 1349 1350 sgl[0].gpa_page = rc->rc_gpa; 1351 sgl[0].gpa_len = hdr->rm_len; 1352 sgl[0].gpa_ofs = 0; 1353 1354 rc->rc_done = 0; 1355 1356 hvn_submit_cmd(sc, rc); 1357 1358 do { 1359 rv = hv_channel_send_sgl(sc->sc_chan, sgl, 1, &rc->rc_msg, 1360 sizeof(*msg), rc->rc_id); 1361 if (rv == EAGAIN) { 1362 if (cold) 1363 delay(100); 1364 else { 1365 tsleep_nsec(rc, PRIBIO, "rndisout", 1366 USEC_TO_NSEC(100)); 1367 } 1368 } else if (rv) { 1369 DPRINTF("%s: RNDIS operation %u send error %d\n", 1370 sc->sc_dev.dv_xname, hdr->rm_type, rv); 1371 hvn_rollback_cmd(sc, rc); 1372 return (rv); 1373 } 1374 } while (rv != 0 && --tries > 0); 1375 1376 if (tries == 0 && rv != 0) { 1377 printf("%s: RNDIS operation %u send error %d\n", 1378 sc->sc_dev.dv_xname, hdr->rm_type, rv); 1379 return (rv); 1380 } 1381 1382 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1383 BUS_DMASYNC_POSTWRITE); 1384 1385 do { 1386 if (cold) 1387 delay(1000); 1388 else { 1389 tsleep_nsec(rc, PRIBIO | PCATCH, "rndiscmd", 1390 USEC_TO_NSEC(1000)); 1391 } 1392 s = splnet(); 1393 hvn_nvs_intr(sc); 1394 splx(s); 1395 } while (--timo > 0 && rc->rc_done != 1); 1396 1397 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1398 BUS_DMASYNC_POSTREAD); 1399 1400 if (rc->rc_done != 1) { 1401 rv = timo == 0 ? ETIMEDOUT : EINTR; 1402 if (hvn_rollback_cmd(sc, rc)) { 1403 hvn_release_cmd(sc, rc); 1404 rv = 0; 1405 } else if (rv == ETIMEDOUT) { 1406 printf("%s: RNDIS operation %u timed out\n", 1407 sc->sc_dev.dv_xname, hdr->rm_type); 1408 } 1409 return (rv); 1410 } 1411 1412 hvn_release_cmd(sc, rc); 1413 return (0); 1414 } 1415 1416 void 1417 hvn_rndis_input(struct hvn_softc *sc, uint64_t tid, void *arg) 1418 { 1419 struct ifnet *ifp = &sc->sc_ac.ac_if; 1420 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1421 struct vmbus_chanpkt_prplist *cp = arg; 1422 uint32_t off, len, type; 1423 int i; 1424 1425 if (sc->sc_rx_ring == NULL) { 1426 DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname); 1427 return; 1428 } 1429 for (i = 0; i < cp->cp_range_cnt; i++) { 1430 off = cp->cp_range[i].gpa_ofs; 1431 len = cp->cp_range[i].gpa_len; 1432 1433 KASSERT(off + len <= sc->sc_rx_size); 1434 KASSERT(len >= RNDIS_HEADER_OFFSET + 4); 1435 1436 memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type)); 1437 switch (type) { 1438 /* data message */ 1439 case REMOTE_NDIS_PACKET_MSG: 1440 hvn_rxeof(sc, (caddr_t)sc->sc_rx_ring + 1441 off, len, &ml); 1442 break; 1443 /* completion messages */ 1444 case REMOTE_NDIS_INITIALIZE_CMPLT: 1445 case REMOTE_NDIS_QUERY_CMPLT: 1446 case REMOTE_NDIS_SET_CMPLT: 1447 case REMOTE_NDIS_RESET_CMPLT: 1448 case REMOTE_NDIS_KEEPALIVE_CMPLT: 1449 hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring + 1450 off, len); 1451 break; 1452 /* notification message */ 1453 case REMOTE_NDIS_INDICATE_STATUS_MSG: 1454 hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring + 1455 off, len); 1456 break; 1457 default: 1458 printf("%s: unhandled RNDIS message type %u\n", 1459 sc->sc_dev.dv_xname, type); 1460 } 1461 } 1462 hvn_nvs_ack(sc, tid); 1463 1464 if (ifp->if_flags & IFF_RUNNING) 1465 if_input(ifp, &ml); 1466 else 1467 ml_purge(&ml); 1468 } 1469 1470 static inline struct mbuf * 1471 hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len) 1472 { 1473 struct mbuf *m; 1474 1475 if (len + ETHER_ALIGN <= MHLEN) 1476 MGETHDR(m, M_NOWAIT, MT_DATA); 1477 else 1478 m = MCLGETL(NULL, M_NOWAIT, len + ETHER_ALIGN); 1479 if (m == NULL) 1480 return (NULL); 1481 m->m_len = m->m_pkthdr.len = len; 1482 m_adj(m, ETHER_ALIGN); 1483 1484 if (m_copyback(m, 0, len, buf, M_NOWAIT)) { 1485 m_freem(m); 1486 return (NULL); 1487 } 1488 1489 return (m); 1490 } 1491 1492 void 1493 hvn_rxeof(struct hvn_softc *sc, caddr_t buf, uint32_t len, struct mbuf_list *ml) 1494 { 1495 struct ifnet *ifp = &sc->sc_ac.ac_if; 1496 struct rndis_packet_msg *pkt; 1497 struct rndis_pktinfo *pi; 1498 uint32_t csum, vlan; 1499 struct mbuf *m; 1500 1501 if (!(ifp->if_flags & IFF_RUNNING)) 1502 return; 1503 1504 if (len < sizeof(*pkt)) { 1505 printf("%s: data packet too short: %u\n", 1506 sc->sc_dev.dv_xname, len); 1507 return; 1508 } 1509 1510 pkt = (struct rndis_packet_msg *)buf; 1511 1512 if (pkt->rm_dataoffset + pkt->rm_datalen > len) { 1513 printf("%s: data packet out of bounds: %u@%u\n", 1514 sc->sc_dev.dv_xname, pkt->rm_dataoffset, pkt->rm_datalen); 1515 return; 1516 } 1517 1518 if ((m = hvn_devget(sc, buf + RNDIS_HEADER_OFFSET + pkt->rm_dataoffset, 1519 pkt->rm_datalen)) == NULL) { 1520 ifp->if_ierrors++; 1521 return; 1522 } 1523 1524 if (pkt->rm_pktinfooffset + pkt->rm_pktinfolen > len) { 1525 printf("%s: pktinfo is out of bounds: %u@%u vs %u\n", 1526 sc->sc_dev.dv_xname, pkt->rm_pktinfolen, 1527 pkt->rm_pktinfooffset, len); 1528 goto done; 1529 } 1530 pi = (struct rndis_pktinfo *)((caddr_t)pkt + RNDIS_HEADER_OFFSET + 1531 pkt->rm_pktinfooffset); 1532 while (pkt->rm_pktinfolen > 0) { 1533 if (pi->rm_size > pkt->rm_pktinfolen) { 1534 printf("%s: invalid pktinfo size: %u/%u\n", 1535 sc->sc_dev.dv_xname, pi->rm_size, 1536 pkt->rm_pktinfolen); 1537 break; 1538 } 1539 switch (pi->rm_type) { 1540 case NDIS_PKTINFO_TYPE_CSUM: 1541 memcpy(&csum, pi->rm_data, sizeof(csum)); 1542 if (csum & NDIS_RXCSUM_INFO_IPCS_OK) 1543 m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 1544 if (csum & NDIS_RXCSUM_INFO_TCPCS_OK) 1545 m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK; 1546 if (csum & NDIS_RXCSUM_INFO_UDPCS_OK) 1547 m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK; 1548 break; 1549 case NDIS_PKTINFO_TYPE_VLAN: 1550 memcpy(&vlan, pi->rm_data, sizeof(vlan)); 1551 #if NVLAN > 0 1552 if (vlan != 0xffffffff) { 1553 m->m_pkthdr.ether_vtag = 1554 NDIS_VLAN_INFO_ID(vlan) | 1555 (NDIS_VLAN_INFO_PRI(vlan) << EVL_PRIO_BITS); 1556 m->m_flags |= M_VLANTAG; 1557 } 1558 #endif 1559 break; 1560 default: 1561 DPRINTF("%s: unhandled pktinfo type %u\n", 1562 sc->sc_dev.dv_xname, pi->rm_type); 1563 } 1564 pkt->rm_pktinfolen -= pi->rm_size; 1565 pi = (struct rndis_pktinfo *)((caddr_t)pi + pi->rm_size); 1566 } 1567 1568 done: 1569 ml_enqueue(ml, m); 1570 } 1571 1572 void 1573 hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len) 1574 { 1575 struct rndis_cmd *rc; 1576 uint32_t id; 1577 1578 memcpy(&id, buf + RNDIS_HEADER_OFFSET, sizeof(id)); 1579 if ((rc = hvn_complete_cmd(sc, id)) != NULL) { 1580 if (len < rc->rc_cmplen) 1581 printf("%s: RNDIS response %u too short: %u\n", 1582 sc->sc_dev.dv_xname, id, len); 1583 else 1584 memcpy(&rc->rc_cmp, buf, rc->rc_cmplen); 1585 if (len > rc->rc_cmplen && 1586 len - rc->rc_cmplen > HVN_RNDIS_BUFSIZE) 1587 printf("%s: RNDIS response %u too large: %u\n", 1588 sc->sc_dev.dv_xname, id, len); 1589 else if (len > rc->rc_cmplen) 1590 memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen, 1591 len - rc->rc_cmplen); 1592 rc->rc_done = 1; 1593 wakeup_one(rc); 1594 } else 1595 DPRINTF("%s: failed to complete RNDIS request id %u\n", 1596 sc->sc_dev.dv_xname, id); 1597 } 1598 1599 int 1600 hvn_rndis_output(struct hvn_softc *sc, struct hvn_tx_desc *txd) 1601 { 1602 uint64_t rid = (uint64_t)txd->txd_id << 32; 1603 int rv; 1604 1605 rv = hv_channel_send_sgl(sc->sc_chan, txd->txd_sgl, txd->txd_nsge, 1606 &sc->sc_data_msg, sizeof(sc->sc_data_msg), rid); 1607 if (rv) { 1608 DPRINTF("%s: RNDIS data send error %d\n", 1609 sc->sc_dev.dv_xname, rv); 1610 return (rv); 1611 } 1612 1613 return (0); 1614 } 1615 1616 void 1617 hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len) 1618 { 1619 uint32_t status; 1620 1621 memcpy(&status, buf + RNDIS_HEADER_OFFSET, sizeof(status)); 1622 switch (status) { 1623 case RNDIS_STATUS_MEDIA_CONNECT: 1624 sc->sc_link_state = LINK_STATE_UP; 1625 break; 1626 case RNDIS_STATUS_MEDIA_DISCONNECT: 1627 sc->sc_link_state = LINK_STATE_DOWN; 1628 break; 1629 /* Ignore these */ 1630 case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG: 1631 return; 1632 default: 1633 DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname, 1634 status); 1635 return; 1636 } 1637 KERNEL_LOCK(); 1638 hvn_link_status(sc); 1639 KERNEL_UNLOCK(); 1640 } 1641 1642 int 1643 hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length) 1644 { 1645 struct rndis_cmd *rc; 1646 struct rndis_query_req *req; 1647 struct rndis_query_comp *cmp; 1648 size_t olength = *length; 1649 int rv; 1650 1651 rc = hvn_alloc_cmd(sc); 1652 1653 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1654 BUS_DMASYNC_PREREAD); 1655 1656 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid); 1657 1658 req = rc->rc_req; 1659 req->rm_type = REMOTE_NDIS_QUERY_MSG; 1660 req->rm_len = sizeof(*req); 1661 req->rm_rid = rc->rc_id; 1662 req->rm_oid = oid; 1663 req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET; 1664 1665 rc->rc_cmplen = sizeof(*cmp); 1666 1667 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1668 BUS_DMASYNC_PREWRITE); 1669 1670 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) { 1671 DPRINTF("%s: QUERY_MSG failed, error %d\n", 1672 sc->sc_dev.dv_xname, rv); 1673 hvn_free_cmd(sc, rc); 1674 return (rv); 1675 } 1676 1677 cmp = (struct rndis_query_comp *)&rc->rc_cmp; 1678 switch (cmp->rm_status) { 1679 case RNDIS_STATUS_SUCCESS: 1680 if (cmp->rm_infobuflen > olength) { 1681 rv = EINVAL; 1682 break; 1683 } 1684 memcpy(res, rc->rc_cmpbuf, cmp->rm_infobuflen); 1685 *length = cmp->rm_infobuflen; 1686 break; 1687 default: 1688 *length = 0; 1689 rv = EIO; 1690 } 1691 1692 hvn_free_cmd(sc, rc); 1693 1694 return (rv); 1695 } 1696 1697 int 1698 hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length) 1699 { 1700 struct rndis_cmd *rc; 1701 struct rndis_set_req *req; 1702 struct rndis_set_comp *cmp; 1703 int rv; 1704 1705 rc = hvn_alloc_cmd(sc); 1706 1707 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1708 BUS_DMASYNC_PREREAD); 1709 1710 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid); 1711 1712 req = rc->rc_req; 1713 req->rm_type = REMOTE_NDIS_SET_MSG; 1714 req->rm_len = sizeof(*req) + length; 1715 req->rm_rid = rc->rc_id; 1716 req->rm_oid = oid; 1717 req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET; 1718 1719 rc->rc_cmplen = sizeof(*cmp); 1720 1721 if (length > 0) { 1722 KASSERT(sizeof(*req) + length < PAGE_SIZE); 1723 req->rm_infobuflen = length; 1724 memcpy((caddr_t)(req + 1), data, length); 1725 } 1726 1727 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1728 BUS_DMASYNC_PREWRITE); 1729 1730 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) { 1731 DPRINTF("%s: SET_MSG failed, error %d\n", 1732 sc->sc_dev.dv_xname, rv); 1733 hvn_free_cmd(sc, rc); 1734 return (rv); 1735 } 1736 1737 cmp = (struct rndis_set_comp *)&rc->rc_cmp; 1738 if (cmp->rm_status != RNDIS_STATUS_SUCCESS) 1739 rv = EIO; 1740 1741 hvn_free_cmd(sc, rc); 1742 1743 return (rv); 1744 } 1745 1746 int 1747 hvn_rndis_close(struct hvn_softc *sc) 1748 { 1749 uint32_t filter = 0; 1750 int rv; 1751 1752 rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER, 1753 &filter, sizeof(filter)); 1754 if (rv) 1755 DPRINTF("%s: failed to clear RNDIS filter\n", 1756 sc->sc_dev.dv_xname); 1757 return (rv); 1758 } 1759 1760 void 1761 hvn_rndis_detach(struct hvn_softc *sc) 1762 { 1763 struct rndis_cmd *rc; 1764 struct rndis_halt_req *req; 1765 int rv; 1766 1767 rc = hvn_alloc_cmd(sc); 1768 1769 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1770 BUS_DMASYNC_PREREAD); 1771 1772 rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid); 1773 1774 req = rc->rc_req; 1775 req->rm_type = REMOTE_NDIS_HALT_MSG; 1776 req->rm_len = sizeof(*req); 1777 req->rm_rid = rc->rc_id; 1778 1779 bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE, 1780 BUS_DMASYNC_PREWRITE); 1781 1782 if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) 1783 DPRINTF("%s: HALT_MSG failed, error %d\n", 1784 sc->sc_dev.dv_xname, rv); 1785 1786 hvn_free_cmd(sc, rc); 1787 } 1788