hn_nvs.c revision 307081
1250199Sgrehan/*- 2302045Ssephe * Copyright (c) 2009-2012,2016 Microsoft Corp. 3250199Sgrehan * Copyright (c) 2010-2012 Citrix Inc. 4250199Sgrehan * Copyright (c) 2012 NetApp Inc. 5250199Sgrehan * All rights reserved. 6250199Sgrehan * 7250199Sgrehan * Redistribution and use in source and binary forms, with or without 8250199Sgrehan * modification, are permitted provided that the following conditions 9250199Sgrehan * are met: 10250199Sgrehan * 1. Redistributions of source code must retain the above copyright 11250199Sgrehan * notice unmodified, this list of conditions, and the following 12250199Sgrehan * disclaimer. 13250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 14250199Sgrehan * notice, this list of conditions and the following disclaimer in the 15250199Sgrehan * documentation and/or other materials provided with the distribution. 16250199Sgrehan * 17250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18250199Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19250199Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20250199Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21250199Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22250199Sgrehan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23250199Sgrehan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24250199Sgrehan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25250199Sgrehan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26250199Sgrehan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27266794Smarius * 28266794Smarius * $FreeBSD: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.c 307081 2016-10-12 02:15:06Z sephe $ 29250199Sgrehan */ 30250199Sgrehan 31250199Sgrehan/** 32250199Sgrehan * HyperV vmbus network VSC (virtual services client) module 33250199Sgrehan * 34250199Sgrehan */ 35250199Sgrehan 36250199Sgrehan 37250199Sgrehan#include <sys/param.h> 38250199Sgrehan#include <sys/kernel.h> 39250199Sgrehan#include <sys/socket.h> 40250199Sgrehan#include <sys/lock.h> 41250199Sgrehan#include <net/if.h> 42250199Sgrehan#include <net/if_arp.h> 43250199Sgrehan#include <machine/bus.h> 44250199Sgrehan#include <machine/atomic.h> 45250199Sgrehan 46250199Sgrehan#include <dev/hyperv/include/hyperv.h> 47250199Sgrehan#include "hv_net_vsc.h" 48250199Sgrehan#include "hv_rndis.h" 49250199Sgrehan#include "hv_rndis_filter.h" 50250199Sgrehan 51301918Ssephe/* priv1 and priv2 are consumed by the main driver */ 52301918Ssephe#define hv_chan_rdbuf hv_chan_priv3 53301918Ssephe 54285236SwhuMALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); 55250199Sgrehan 56250199Sgrehan/* 57250199Sgrehan * Forward declarations 58250199Sgrehan */ 59301943Ssephestatic void hv_nv_on_channel_callback(void *xchan); 60307022Ssephestatic int hv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc); 61307022Ssephestatic int hv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *); 62250199Sgrehanstatic int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); 63250199Sgrehanstatic int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev); 64307022Ssephestatic int hv_nv_connect_to_vsp(struct hn_softc *sc); 65285236Swhustatic void hv_nv_on_send_completion(netvsc_dev *net_dev, 66307080Ssephe struct hv_vmbus_channel *, const struct vmbus_chanpkt_hdr *pkt); 67301918Ssephestatic void hv_nv_on_receive_completion(struct hv_vmbus_channel *chan, 68301918Ssephe uint64_t tid, uint32_t status); 69285236Swhustatic void hv_nv_on_receive(netvsc_dev *net_dev, 70307022Ssephe struct hn_softc *sc, struct hv_vmbus_channel *chan, 71307080Ssephe const struct vmbus_chanpkt_hdr *pkt); 72250199Sgrehan 73250199Sgrehan/* 74250199Sgrehan * 75250199Sgrehan */ 76250199Sgrehanstatic inline netvsc_dev * 77307022Ssephehv_nv_alloc_net_device(struct hn_softc *sc) 78250199Sgrehan{ 79250199Sgrehan netvsc_dev *net_dev; 80250199Sgrehan 81301859Ssephe net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_WAITOK | M_ZERO); 82250199Sgrehan 83307022Ssephe net_dev->sc = sc; 84250199Sgrehan net_dev->destroy = FALSE; 85250199Sgrehan sc->net_dev = net_dev; 86250199Sgrehan 87250199Sgrehan return (net_dev); 88250199Sgrehan} 89250199Sgrehan 90250199Sgrehan/* 91307022Ssephe * XXX unnecessary; nuke it. 92250199Sgrehan */ 93250199Sgrehanstatic inline netvsc_dev * 94307022Ssephehv_nv_get_outbound_net_device(struct hn_softc *sc) 95250199Sgrehan{ 96307022Ssephe return sc->net_dev; 97250199Sgrehan} 98250199Sgrehan 99250199Sgrehan/* 100307022Ssephe * XXX unnecessary; nuke it. 101250199Sgrehan */ 102250199Sgrehanstatic inline netvsc_dev * 103307022Ssephehv_nv_get_inbound_net_device(struct hn_softc *sc) 104250199Sgrehan{ 105307022Ssephe return sc->net_dev; 106250199Sgrehan} 107250199Sgrehan 108285236Swhuint 109285236Swhuhv_nv_get_next_send_section(netvsc_dev *net_dev) 110285236Swhu{ 111285236Swhu unsigned long bitsmap_words = net_dev->bitsmap_words; 112285236Swhu unsigned long *bitsmap = net_dev->send_section_bitsmap; 113285236Swhu unsigned long idx; 114285236Swhu int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; 115285236Swhu int i; 116285236Swhu 117285236Swhu for (i = 0; i < bitsmap_words; i++) { 118301857Ssephe idx = ffsl(~bitsmap[i]); 119285236Swhu if (0 == idx) 120285236Swhu continue; 121285236Swhu 122285236Swhu idx--; 123301857Ssephe KASSERT(i * BITS_PER_LONG + idx < net_dev->send_section_count, 124301857Ssephe ("invalid i %d and idx %lu", i, idx)); 125285236Swhu 126301857Ssephe if (atomic_testandset_long(&bitsmap[i], idx)) 127285236Swhu continue; 128285236Swhu 129285236Swhu ret = i * BITS_PER_LONG + idx; 130285236Swhu break; 131285236Swhu } 132285236Swhu 133285236Swhu return (ret); 134285236Swhu} 135285236Swhu 136250199Sgrehan/* 137250199Sgrehan * Net VSC initialize receive buffer with net VSP 138250199Sgrehan * 139250199Sgrehan * Net VSP: Network virtual services client, also known as the 140250199Sgrehan * Hyper-V extensible switch and the synthetic data path. 141250199Sgrehan */ 142250199Sgrehanstatic int 143307022Ssephehv_nv_init_rx_buffer_with_net_vsp(struct hn_softc *sc) 144250199Sgrehan{ 145250199Sgrehan netvsc_dev *net_dev; 146250199Sgrehan nvsp_msg *init_pkt; 147250199Sgrehan int ret = 0; 148250199Sgrehan 149307022Ssephe net_dev = hv_nv_get_outbound_net_device(sc); 150250199Sgrehan if (!net_dev) { 151250199Sgrehan return (ENODEV); 152250199Sgrehan } 153250199Sgrehan 154307081Ssephe net_dev->rx_buf = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 155307081Ssephe PAGE_SIZE, 0, net_dev->rx_buf_size, &net_dev->rxbuf_dma, 156307081Ssephe BUS_DMA_WAITOK | BUS_DMA_ZERO); 157307081Ssephe if (net_dev->rx_buf == NULL) { 158307081Ssephe device_printf(sc->hn_dev, "allocate rxbuf failed\n"); 159307081Ssephe return ENOMEM; 160307081Ssephe } 161250199Sgrehan 162250199Sgrehan /* 163307081Ssephe * Connect the RXBUF GPADL to the primary channel. 164307081Ssephe * 165307081Ssephe * NOTE: 166307081Ssephe * Only primary channel has RXBUF connected to it. Sub-channels 167307081Ssephe * just share this RXBUF. 168250199Sgrehan */ 169307081Ssephe ret = vmbus_chan_gpadl_connect(sc->hn_prichan, 170307081Ssephe net_dev->rxbuf_dma.hv_paddr, net_dev->rx_buf_size, 171307081Ssephe &net_dev->rx_buf_gpadl_handle); 172250199Sgrehan if (ret != 0) { 173307081Ssephe device_printf(sc->hn_dev, "rxbuf gpadl connect failed: %d\n", 174307081Ssephe ret); 175250199Sgrehan goto cleanup; 176250199Sgrehan } 177250199Sgrehan 178250199Sgrehan /* sema_wait(&ext->channel_init_sema); KYS CHECK */ 179250199Sgrehan 180250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 181250199Sgrehan init_pkt = &net_dev->channel_init_packet; 182250199Sgrehan 183250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 184250199Sgrehan 185250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf; 186250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 187250199Sgrehan net_dev->rx_buf_gpadl_handle; 188250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 189250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 190250199Sgrehan 191250199Sgrehan /* Send the gpadl notification request */ 192250199Sgrehan 193307079Ssephe ret = vmbus_chan_send(sc->hn_prichan, 194307079Ssephe VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 195307079Ssephe init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt); 196250199Sgrehan if (ret != 0) { 197250199Sgrehan goto cleanup; 198250199Sgrehan } 199250199Sgrehan 200250199Sgrehan sema_wait(&net_dev->channel_init_sema); 201250199Sgrehan 202250199Sgrehan /* Check the response */ 203250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status 204250199Sgrehan != nvsp_status_success) { 205250199Sgrehan ret = EINVAL; 206250199Sgrehan goto cleanup; 207250199Sgrehan } 208250199Sgrehan 209250199Sgrehan net_dev->rx_section_count = 210250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; 211250199Sgrehan 212250199Sgrehan net_dev->rx_sections = malloc(net_dev->rx_section_count * 213301859Ssephe sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_WAITOK); 214250199Sgrehan memcpy(net_dev->rx_sections, 215250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections, 216250199Sgrehan net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section)); 217250199Sgrehan 218250199Sgrehan 219250199Sgrehan /* 220250199Sgrehan * For first release, there should only be 1 section that represents 221250199Sgrehan * the entire receive buffer 222250199Sgrehan */ 223250199Sgrehan if (net_dev->rx_section_count != 1 224250199Sgrehan || net_dev->rx_sections->offset != 0) { 225250199Sgrehan ret = EINVAL; 226250199Sgrehan goto cleanup; 227250199Sgrehan } 228250199Sgrehan 229250199Sgrehan goto exit; 230250199Sgrehan 231250199Sgrehancleanup: 232250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 233250199Sgrehan 234250199Sgrehanexit: 235250199Sgrehan return (ret); 236250199Sgrehan} 237250199Sgrehan 238250199Sgrehan/* 239250199Sgrehan * Net VSC initialize send buffer with net VSP 240250199Sgrehan */ 241250199Sgrehanstatic int 242307022Ssephehv_nv_init_send_buffer_with_net_vsp(struct hn_softc *sc) 243250199Sgrehan{ 244250199Sgrehan netvsc_dev *net_dev; 245250199Sgrehan nvsp_msg *init_pkt; 246250199Sgrehan int ret = 0; 247250199Sgrehan 248307022Ssephe net_dev = hv_nv_get_outbound_net_device(sc); 249250199Sgrehan if (!net_dev) { 250250199Sgrehan return (ENODEV); 251250199Sgrehan } 252250199Sgrehan 253307081Ssephe net_dev->send_buf = hyperv_dmamem_alloc(bus_get_dma_tag(sc->hn_dev), 254307081Ssephe PAGE_SIZE, 0, net_dev->send_buf_size, &net_dev->txbuf_dma, 255307081Ssephe BUS_DMA_WAITOK | BUS_DMA_ZERO); 256250199Sgrehan if (net_dev->send_buf == NULL) { 257307081Ssephe device_printf(sc->hn_dev, "allocate chimney txbuf failed\n"); 258307081Ssephe return ENOMEM; 259250199Sgrehan } 260250199Sgrehan 261250199Sgrehan /* 262307081Ssephe * Connect chimney sending buffer GPADL to the primary channel. 263307081Ssephe * 264307081Ssephe * NOTE: 265307081Ssephe * Only primary channel has chimney sending buffer connected to it. 266307081Ssephe * Sub-channels just share this chimney sending buffer. 267250199Sgrehan */ 268307081Ssephe ret = vmbus_chan_gpadl_connect(sc->hn_prichan, 269307081Ssephe net_dev->txbuf_dma.hv_paddr, net_dev->send_buf_size, 270250199Sgrehan &net_dev->send_buf_gpadl_handle); 271250199Sgrehan if (ret != 0) { 272307081Ssephe device_printf(sc->hn_dev, "chimney sending buffer gpadl " 273307081Ssephe "connect failed: %d\n", ret); 274250199Sgrehan goto cleanup; 275250199Sgrehan } 276250199Sgrehan 277250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 278250199Sgrehan 279250199Sgrehan init_pkt = &net_dev->channel_init_packet; 280250199Sgrehan 281250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 282250199Sgrehan 283250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf; 284250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 285250199Sgrehan net_dev->send_buf_gpadl_handle; 286250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 287250199Sgrehan NETVSC_SEND_BUFFER_ID; 288250199Sgrehan 289250199Sgrehan /* Send the gpadl notification request */ 290250199Sgrehan 291307079Ssephe ret = vmbus_chan_send(sc->hn_prichan, 292307079Ssephe VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 293307079Ssephe init_pkt, sizeof(nvsp_msg), (uint64_t)init_pkt); 294250199Sgrehan if (ret != 0) { 295250199Sgrehan goto cleanup; 296250199Sgrehan } 297250199Sgrehan 298250199Sgrehan sema_wait(&net_dev->channel_init_sema); 299250199Sgrehan 300250199Sgrehan /* Check the response */ 301250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status 302250199Sgrehan != nvsp_status_success) { 303250199Sgrehan ret = EINVAL; 304250199Sgrehan goto cleanup; 305250199Sgrehan } 306250199Sgrehan 307250199Sgrehan net_dev->send_section_size = 308250199Sgrehan init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; 309285236Swhu net_dev->send_section_count = 310285236Swhu net_dev->send_buf_size / net_dev->send_section_size; 311285236Swhu net_dev->bitsmap_words = howmany(net_dev->send_section_count, 312285236Swhu BITS_PER_LONG); 313285236Swhu net_dev->send_section_bitsmap = 314285236Swhu malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC, 315301859Ssephe M_WAITOK | M_ZERO); 316250199Sgrehan 317250199Sgrehan goto exit; 318250199Sgrehan 319250199Sgrehancleanup: 320250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 321250199Sgrehan 322250199Sgrehanexit: 323250199Sgrehan return (ret); 324250199Sgrehan} 325250199Sgrehan 326250199Sgrehan/* 327250199Sgrehan * Net VSC destroy receive buffer 328250199Sgrehan */ 329250199Sgrehanstatic int 330250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev) 331250199Sgrehan{ 332250199Sgrehan nvsp_msg *revoke_pkt; 333250199Sgrehan int ret = 0; 334250199Sgrehan 335250199Sgrehan /* 336250199Sgrehan * If we got a section count, it means we received a 337250199Sgrehan * send_rx_buf_complete msg 338250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 339250199Sgrehan * we need to send a revoke msg here 340250199Sgrehan */ 341250199Sgrehan if (net_dev->rx_section_count) { 342250199Sgrehan /* Send the revoke receive buffer */ 343250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 344250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 345250199Sgrehan 346250199Sgrehan revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf; 347250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id = 348250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 349250199Sgrehan 350307079Ssephe ret = vmbus_chan_send(net_dev->sc->hn_prichan, 351307079Ssephe VMBUS_CHANPKT_TYPE_INBAND, 0, revoke_pkt, sizeof(nvsp_msg), 352307079Ssephe (uint64_t)(uintptr_t)revoke_pkt); 353250199Sgrehan 354250199Sgrehan /* 355250199Sgrehan * If we failed here, we might as well return and have a leak 356250199Sgrehan * rather than continue and a bugchk 357250199Sgrehan */ 358250199Sgrehan if (ret != 0) { 359250199Sgrehan return (ret); 360250199Sgrehan } 361250199Sgrehan } 362250199Sgrehan 363250199Sgrehan /* Tear down the gpadl on the vsp end */ 364250199Sgrehan if (net_dev->rx_buf_gpadl_handle) { 365307022Ssephe ret = hv_vmbus_channel_teardown_gpdal(net_dev->sc->hn_prichan, 366250199Sgrehan net_dev->rx_buf_gpadl_handle); 367250199Sgrehan /* 368250199Sgrehan * If we failed here, we might as well return and have a leak 369250199Sgrehan * rather than continue and a bugchk 370250199Sgrehan */ 371250199Sgrehan if (ret != 0) { 372250199Sgrehan return (ret); 373250199Sgrehan } 374250199Sgrehan net_dev->rx_buf_gpadl_handle = 0; 375250199Sgrehan } 376250199Sgrehan 377250199Sgrehan if (net_dev->rx_buf) { 378250199Sgrehan /* Free up the receive buffer */ 379307081Ssephe hyperv_dmamem_free(&net_dev->rxbuf_dma, net_dev->rx_buf); 380250199Sgrehan net_dev->rx_buf = NULL; 381250199Sgrehan } 382250199Sgrehan 383250199Sgrehan if (net_dev->rx_sections) { 384285236Swhu free(net_dev->rx_sections, M_NETVSC); 385250199Sgrehan net_dev->rx_sections = NULL; 386250199Sgrehan net_dev->rx_section_count = 0; 387250199Sgrehan } 388250199Sgrehan 389250199Sgrehan return (ret); 390250199Sgrehan} 391250199Sgrehan 392250199Sgrehan/* 393250199Sgrehan * Net VSC destroy send buffer 394250199Sgrehan */ 395250199Sgrehanstatic int 396250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev) 397250199Sgrehan{ 398250199Sgrehan nvsp_msg *revoke_pkt; 399250199Sgrehan int ret = 0; 400250199Sgrehan 401250199Sgrehan /* 402250199Sgrehan * If we got a section count, it means we received a 403250199Sgrehan * send_rx_buf_complete msg 404250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 405250199Sgrehan * we need to send a revoke msg here 406250199Sgrehan */ 407250199Sgrehan if (net_dev->send_section_size) { 408250199Sgrehan /* Send the revoke send buffer */ 409250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 410250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 411250199Sgrehan 412250199Sgrehan revoke_pkt->hdr.msg_type = 413250199Sgrehan nvsp_msg_1_type_revoke_send_buf; 414250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id = 415250199Sgrehan NETVSC_SEND_BUFFER_ID; 416250199Sgrehan 417307079Ssephe ret = vmbus_chan_send(net_dev->sc->hn_prichan, 418307079Ssephe VMBUS_CHANPKT_TYPE_INBAND, 0, 419250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 420307079Ssephe (uint64_t)(uintptr_t)revoke_pkt); 421250199Sgrehan /* 422250199Sgrehan * If we failed here, we might as well return and have a leak 423250199Sgrehan * rather than continue and a bugchk 424250199Sgrehan */ 425250199Sgrehan if (ret != 0) { 426250199Sgrehan return (ret); 427250199Sgrehan } 428250199Sgrehan } 429250199Sgrehan 430250199Sgrehan /* Tear down the gpadl on the vsp end */ 431250199Sgrehan if (net_dev->send_buf_gpadl_handle) { 432307022Ssephe ret = hv_vmbus_channel_teardown_gpdal(net_dev->sc->hn_prichan, 433250199Sgrehan net_dev->send_buf_gpadl_handle); 434250199Sgrehan 435250199Sgrehan /* 436250199Sgrehan * If we failed here, we might as well return and have a leak 437250199Sgrehan * rather than continue and a bugchk 438250199Sgrehan */ 439250199Sgrehan if (ret != 0) { 440250199Sgrehan return (ret); 441250199Sgrehan } 442250199Sgrehan net_dev->send_buf_gpadl_handle = 0; 443250199Sgrehan } 444250199Sgrehan 445250199Sgrehan if (net_dev->send_buf) { 446250199Sgrehan /* Free up the receive buffer */ 447307081Ssephe hyperv_dmamem_free(&net_dev->txbuf_dma, net_dev->send_buf); 448250199Sgrehan net_dev->send_buf = NULL; 449250199Sgrehan } 450250199Sgrehan 451285236Swhu if (net_dev->send_section_bitsmap) { 452285236Swhu free(net_dev->send_section_bitsmap, M_NETVSC); 453285236Swhu } 454285236Swhu 455250199Sgrehan return (ret); 456250199Sgrehan} 457250199Sgrehan 458250199Sgrehan 459250199Sgrehan/* 460250199Sgrehan * Attempt to negotiate the caller-specified NVSP version 461250199Sgrehan * 462250199Sgrehan * For NVSP v2, Server 2008 R2 does not set 463250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers 464250199Sgrehan * to the negotiated version, so we cannot rely on that. 465250199Sgrehan */ 466250199Sgrehanstatic int 467307022Ssephehv_nv_negotiate_nvsp_protocol(struct hn_softc *sc, netvsc_dev *net_dev, 468285236Swhu uint32_t nvsp_ver) 469250199Sgrehan{ 470250199Sgrehan nvsp_msg *init_pkt; 471250199Sgrehan int ret; 472250199Sgrehan 473250199Sgrehan init_pkt = &net_dev->channel_init_packet; 474250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 475250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_type_init; 476250199Sgrehan 477250199Sgrehan /* 478250199Sgrehan * Specify parameter as the only acceptable protocol version 479250199Sgrehan */ 480250199Sgrehan init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver; 481250199Sgrehan init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver; 482250199Sgrehan 483250199Sgrehan /* Send the init request */ 484307079Ssephe ret = vmbus_chan_send(sc->hn_prichan, 485307079Ssephe VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 486307079Ssephe init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt); 487250199Sgrehan if (ret != 0) 488250199Sgrehan return (-1); 489250199Sgrehan 490250199Sgrehan sema_wait(&net_dev->channel_init_sema); 491250199Sgrehan 492250199Sgrehan if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success) 493250199Sgrehan return (EINVAL); 494250199Sgrehan 495250199Sgrehan return (0); 496250199Sgrehan} 497250199Sgrehan 498250199Sgrehan/* 499250199Sgrehan * Send NDIS version 2 config packet containing MTU. 500250199Sgrehan * 501250199Sgrehan * Not valid for NDIS version 1. 502250199Sgrehan */ 503250199Sgrehanstatic int 504307022Ssephehv_nv_send_ndis_config(struct hn_softc *sc, uint32_t mtu) 505250199Sgrehan{ 506250199Sgrehan netvsc_dev *net_dev; 507250199Sgrehan nvsp_msg *init_pkt; 508250199Sgrehan int ret; 509250199Sgrehan 510307022Ssephe net_dev = hv_nv_get_outbound_net_device(sc); 511250199Sgrehan if (!net_dev) 512250199Sgrehan return (-ENODEV); 513250199Sgrehan 514250199Sgrehan /* 515250199Sgrehan * Set up configuration packet, write MTU 516250199Sgrehan * Indicate we are capable of handling VLAN tags 517250199Sgrehan */ 518250199Sgrehan init_pkt = &net_dev->channel_init_packet; 519250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 520250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config; 521250199Sgrehan init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu; 522250199Sgrehan init_pkt-> 523250199Sgrehan msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q 524250199Sgrehan = 1; 525250199Sgrehan 526250199Sgrehan /* Send the configuration packet */ 527307079Ssephe ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0, 528307079Ssephe init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt); 529250199Sgrehan if (ret != 0) 530250199Sgrehan return (-EINVAL); 531250199Sgrehan 532250199Sgrehan return (0); 533250199Sgrehan} 534250199Sgrehan 535250199Sgrehan/* 536250199Sgrehan * Net VSC connect to VSP 537250199Sgrehan */ 538250199Sgrehanstatic int 539307022Ssephehv_nv_connect_to_vsp(struct hn_softc *sc) 540250199Sgrehan{ 541250199Sgrehan netvsc_dev *net_dev; 542250199Sgrehan nvsp_msg *init_pkt; 543250199Sgrehan uint32_t ndis_version; 544285236Swhu uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1, 545285236Swhu NVSP_PROTOCOL_VERSION_2, 546285236Swhu NVSP_PROTOCOL_VERSION_4, 547285236Swhu NVSP_PROTOCOL_VERSION_5 }; 548285236Swhu int i; 549285236Swhu int protocol_number = nitems(protocol_list); 550250199Sgrehan int ret = 0; 551307022Ssephe device_t dev = sc->hn_dev; 552250199Sgrehan struct ifnet *ifp = sc->arpcom.ac_ifp; 553250199Sgrehan 554307022Ssephe net_dev = hv_nv_get_outbound_net_device(sc); 555250199Sgrehan 556250199Sgrehan /* 557285236Swhu * Negotiate the NVSP version. Try the latest NVSP first. 558250199Sgrehan */ 559285236Swhu for (i = protocol_number - 1; i >= 0; i--) { 560307022Ssephe if (hv_nv_negotiate_nvsp_protocol(sc, net_dev, 561285236Swhu protocol_list[i]) == 0) { 562285236Swhu net_dev->nvsp_version = protocol_list[i]; 563285236Swhu if (bootverbose) 564285236Swhu device_printf(dev, "Netvsc: got version 0x%x\n", 565285236Swhu net_dev->nvsp_version); 566285236Swhu break; 567250199Sgrehan } 568250199Sgrehan } 569250199Sgrehan 570285236Swhu if (i < 0) { 571285236Swhu if (bootverbose) 572285236Swhu device_printf(dev, "failed to negotiate a valid " 573285236Swhu "protocol.\n"); 574285236Swhu return (EPROTO); 575285236Swhu } 576285236Swhu 577250199Sgrehan /* 578250199Sgrehan * Set the MTU if supported by this NVSP protocol version 579250199Sgrehan * This needs to be right after the NVSP init message per Haiyang 580250199Sgrehan */ 581285236Swhu if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) 582307022Ssephe ret = hv_nv_send_ndis_config(sc, ifp->if_mtu); 583250199Sgrehan 584250199Sgrehan /* 585250199Sgrehan * Send the NDIS version 586250199Sgrehan */ 587250199Sgrehan init_pkt = &net_dev->channel_init_packet; 588250199Sgrehan 589250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 590250199Sgrehan 591285236Swhu if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) { 592285236Swhu ndis_version = NDIS_VERSION_6_1; 593285236Swhu } else { 594285236Swhu ndis_version = NDIS_VERSION_6_30; 595285236Swhu } 596250199Sgrehan 597250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; 598250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = 599250199Sgrehan (ndis_version & 0xFFFF0000) >> 16; 600250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers = 601250199Sgrehan ndis_version & 0xFFFF; 602250199Sgrehan 603250199Sgrehan /* Send the init request */ 604250199Sgrehan 605307079Ssephe ret = vmbus_chan_send(sc->hn_prichan, VMBUS_CHANPKT_TYPE_INBAND, 0, 606307079Ssephe init_pkt, sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt); 607250199Sgrehan if (ret != 0) { 608250199Sgrehan goto cleanup; 609250199Sgrehan } 610250199Sgrehan /* 611250199Sgrehan * TODO: BUGBUG - We have to wait for the above msg since the netvsp 612250199Sgrehan * uses KMCL which acknowledges packet (completion packet) 613307034Ssephe * since our Vmbus always set the VMBUS_CHANPKT_FLAG_RC flag 614250199Sgrehan */ 615250199Sgrehan /* sema_wait(&NetVscChannel->channel_init_sema); */ 616250199Sgrehan 617250199Sgrehan /* Post the big receive buffer to NetVSP */ 618295789Ssephe if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_2) 619295789Ssephe net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; 620295789Ssephe else 621295789Ssephe net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; 622295789Ssephe net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; 623295789Ssephe 624307022Ssephe ret = hv_nv_init_rx_buffer_with_net_vsp(sc); 625250199Sgrehan if (ret == 0) 626307022Ssephe ret = hv_nv_init_send_buffer_with_net_vsp(sc); 627250199Sgrehan 628250199Sgrehancleanup: 629250199Sgrehan return (ret); 630250199Sgrehan} 631250199Sgrehan 632250199Sgrehan/* 633250199Sgrehan * Net VSC disconnect from VSP 634250199Sgrehan */ 635250199Sgrehanstatic void 636250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev) 637250199Sgrehan{ 638250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 639250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 640250199Sgrehan} 641250199Sgrehan 642302048Ssephevoid 643302048Ssephehv_nv_subchan_attach(struct hv_vmbus_channel *chan) 644301943Ssephe{ 645301943Ssephe 646301943Ssephe chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK); 647302048Ssephe hv_vmbus_channel_open(chan, NETVSC_DEVICE_RING_BUFFER_SIZE, 648301943Ssephe NETVSC_DEVICE_RING_BUFFER_SIZE, NULL, 0, 649301943Ssephe hv_nv_on_channel_callback, chan); 650301943Ssephe} 651301943Ssephe 652301943Ssephe/* 653250199Sgrehan * Net VSC on device add 654250199Sgrehan * 655250199Sgrehan * Callback when the device belonging to this driver is added 656250199Sgrehan */ 657250199Sgrehannetvsc_dev * 658307022Ssephehv_nv_on_device_add(struct hn_softc *sc, void *additional_info) 659250199Sgrehan{ 660307022Ssephe struct hv_vmbus_channel *chan = sc->hn_prichan; 661250199Sgrehan netvsc_dev *net_dev; 662285236Swhu int ret = 0; 663250199Sgrehan 664307022Ssephe net_dev = hv_nv_alloc_net_device(sc); 665301918Ssephe if (net_dev == NULL) 666301918Ssephe return NULL; 667250199Sgrehan 668250199Sgrehan /* Initialize the NetVSC channel extension */ 669250199Sgrehan 670250199Sgrehan sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); 671250199Sgrehan 672301918Ssephe chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK); 673301918Ssephe 674250199Sgrehan /* 675250199Sgrehan * Open the channel 676250199Sgrehan */ 677301918Ssephe ret = hv_vmbus_channel_open(chan, 678250199Sgrehan NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE, 679301918Ssephe NULL, 0, hv_nv_on_channel_callback, chan); 680301918Ssephe if (ret != 0) { 681301918Ssephe free(chan->hv_chan_rdbuf, M_NETVSC); 682250199Sgrehan goto cleanup; 683301918Ssephe } 684250199Sgrehan 685250199Sgrehan /* 686250199Sgrehan * Connect with the NetVsp 687250199Sgrehan */ 688307022Ssephe ret = hv_nv_connect_to_vsp(sc); 689250199Sgrehan if (ret != 0) 690250199Sgrehan goto close; 691250199Sgrehan 692250199Sgrehan return (net_dev); 693250199Sgrehan 694250199Sgrehanclose: 695250199Sgrehan /* Now, we can close the channel safely */ 696301918Ssephe free(chan->hv_chan_rdbuf, M_NETVSC); 697301918Ssephe hv_vmbus_channel_close(chan); 698250199Sgrehan 699250199Sgrehancleanup: 700250199Sgrehan /* 701250199Sgrehan * Free the packet buffers on the netvsc device packet queue. 702250199Sgrehan * Release other resources. 703250199Sgrehan */ 704301952Ssephe sema_destroy(&net_dev->channel_init_sema); 705301952Ssephe free(net_dev, M_NETVSC); 706250199Sgrehan 707250199Sgrehan return (NULL); 708250199Sgrehan} 709250199Sgrehan 710250199Sgrehan/* 711250199Sgrehan * Net VSC on device remove 712250199Sgrehan */ 713250199Sgrehanint 714307022Ssephehv_nv_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel) 715250199Sgrehan{ 716250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 717250199Sgrehan 718250199Sgrehan /* Stop outbound traffic ie sends and receives completions */ 719250199Sgrehan net_dev->destroy = TRUE; 720250199Sgrehan 721250199Sgrehan hv_nv_disconnect_from_vsp(net_dev); 722250199Sgrehan 723250199Sgrehan /* At this point, no one should be accessing net_dev except in here */ 724250199Sgrehan 725250199Sgrehan /* Now, we can close the channel safely */ 726250199Sgrehan 727307022Ssephe free(sc->hn_prichan->hv_chan_rdbuf, M_NETVSC); 728307022Ssephe hv_vmbus_channel_close(sc->hn_prichan); 729250199Sgrehan 730250199Sgrehan sema_destroy(&net_dev->channel_init_sema); 731285236Swhu free(net_dev, M_NETVSC); 732250199Sgrehan 733250199Sgrehan return (0); 734250199Sgrehan} 735250199Sgrehan 736250199Sgrehan/* 737250199Sgrehan * Net VSC on send completion 738250199Sgrehan */ 739285236Swhustatic void 740307022Ssephehv_nv_on_send_completion(netvsc_dev *net_dev, struct hv_vmbus_channel *chan, 741307080Ssephe const struct vmbus_chanpkt_hdr *pkt) 742250199Sgrehan{ 743307080Ssephe const nvsp_msg *nvsp_msg_pkt; 744250199Sgrehan netvsc_packet *net_vsc_pkt; 745250199Sgrehan 746307080Ssephe nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt); 747250199Sgrehan 748250199Sgrehan if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete 749250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 750250199Sgrehan == nvsp_msg_1_type_send_rx_buf_complete 751250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 752301943Ssephe == nvsp_msg_1_type_send_send_buf_complete 753301943Ssephe || nvsp_msg_pkt->hdr.msg_type 754301943Ssephe == nvsp_msg5_type_subchannel) { 755250199Sgrehan /* Copy the response back */ 756250199Sgrehan memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, 757285236Swhu sizeof(nvsp_msg)); 758250199Sgrehan sema_post(&net_dev->channel_init_sema); 759250199Sgrehan } else if (nvsp_msg_pkt->hdr.msg_type == 760285236Swhu nvsp_msg_1_type_send_rndis_pkt_complete) { 761250199Sgrehan /* Get the send context */ 762250199Sgrehan net_vsc_pkt = 763307080Ssephe (netvsc_packet *)(unsigned long)pkt->cph_xactid; 764285236Swhu if (NULL != net_vsc_pkt) { 765285236Swhu if (net_vsc_pkt->send_buf_section_idx != 766285236Swhu NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { 767301857Ssephe u_long mask; 768301857Ssephe int idx; 769301857Ssephe 770301857Ssephe idx = net_vsc_pkt->send_buf_section_idx / 771301857Ssephe BITS_PER_LONG; 772301857Ssephe KASSERT(idx < net_dev->bitsmap_words, 773301857Ssephe ("invalid section index %u", 774301857Ssephe net_vsc_pkt->send_buf_section_idx)); 775301857Ssephe mask = 1UL << 776301857Ssephe (net_vsc_pkt->send_buf_section_idx % 777301857Ssephe BITS_PER_LONG); 778301857Ssephe 779301857Ssephe KASSERT(net_dev->send_section_bitsmap[idx] & 780301857Ssephe mask, 781301857Ssephe ("index bitmap 0x%lx, section index %u, " 782301857Ssephe "bitmap idx %d, bitmask 0x%lx", 783301857Ssephe net_dev->send_section_bitsmap[idx], 784301857Ssephe net_vsc_pkt->send_buf_section_idx, 785301857Ssephe idx, mask)); 786301857Ssephe atomic_clear_long( 787301857Ssephe &net_dev->send_section_bitsmap[idx], mask); 788285236Swhu } 789285236Swhu 790285236Swhu /* Notify the layer above us */ 791301943Ssephe net_vsc_pkt->compl.send.on_send_completion(chan, 792285236Swhu net_vsc_pkt->compl.send.send_completion_context); 793250199Sgrehan 794285236Swhu } 795250199Sgrehan } 796250199Sgrehan} 797250199Sgrehan 798250199Sgrehan/* 799250199Sgrehan * Net VSC on send 800250199Sgrehan * Sends a packet on the specified Hyper-V device. 801250199Sgrehan * Returns 0 on success, non-zero on failure. 802250199Sgrehan */ 803250199Sgrehanint 804301912Ssephehv_nv_on_send(struct hv_vmbus_channel *chan, netvsc_packet *pkt) 805250199Sgrehan{ 806250199Sgrehan nvsp_msg send_msg; 807250199Sgrehan int ret; 808250199Sgrehan 809250199Sgrehan send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt; 810250199Sgrehan if (pkt->is_data_pkt) { 811250199Sgrehan /* 0 is RMC_DATA */ 812250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0; 813250199Sgrehan } else { 814250199Sgrehan /* 1 is RMC_CONTROL */ 815250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; 816250199Sgrehan } 817250199Sgrehan 818250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = 819285236Swhu pkt->send_buf_section_idx; 820285236Swhu send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 821285236Swhu pkt->send_buf_section_size; 822250199Sgrehan 823307034Ssephe if (pkt->gpa_cnt) { 824307034Ssephe ret = vmbus_chan_send_sglist(chan, pkt->gpa, pkt->gpa_cnt, 825266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt); 826250199Sgrehan } else { 827307079Ssephe ret = vmbus_chan_send(chan, 828307079Ssephe VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC, 829307079Ssephe &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt); 830250199Sgrehan } 831250199Sgrehan 832250199Sgrehan return (ret); 833250199Sgrehan} 834250199Sgrehan 835250199Sgrehan/* 836250199Sgrehan * Net VSC on receive 837250199Sgrehan * 838250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively 839250199Sgrehan * with virtual addresses. 840250199Sgrehan */ 841285236Swhustatic void 842307022Ssephehv_nv_on_receive(netvsc_dev *net_dev, struct hn_softc *sc, 843307080Ssephe struct hv_vmbus_channel *chan, const struct vmbus_chanpkt_hdr *pkthdr) 844250199Sgrehan{ 845307080Ssephe const struct vmbus_chanpkt_rxbuf *pkt; 846307080Ssephe const nvsp_msg *nvsp_msg_pkt; 847285236Swhu netvsc_packet vsc_pkt; 848285236Swhu netvsc_packet *net_vsc_pkt = &vsc_pkt; 849307022Ssephe device_t dev = sc->hn_dev; 850250199Sgrehan int count = 0; 851250199Sgrehan int i = 0; 852285236Swhu int status = nvsp_status_success; 853250199Sgrehan 854307080Ssephe nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkthdr); 855250199Sgrehan 856250199Sgrehan /* Make sure this is a valid nvsp packet */ 857285236Swhu if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) { 858307080Ssephe device_printf(dev, "packet hdr type %u is invalid!\n", 859307080Ssephe nvsp_msg_pkt->hdr.msg_type); 860250199Sgrehan return; 861285236Swhu } 862250199Sgrehan 863307080Ssephe pkt = (const struct vmbus_chanpkt_rxbuf *)pkthdr; 864250199Sgrehan 865307080Ssephe if (pkt->cp_rxbuf_id != NETVSC_RECEIVE_BUFFER_ID) { 866307080Ssephe device_printf(dev, "rxbuf_id %d is invalid!\n", 867307080Ssephe pkt->cp_rxbuf_id); 868250199Sgrehan return; 869250199Sgrehan } 870250199Sgrehan 871307080Ssephe count = pkt->cp_rxbuf_cnt; 872250199Sgrehan 873285236Swhu /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 874285236Swhu for (i = 0; i < count; i++) { 875285236Swhu net_vsc_pkt->status = nvsp_status_success; 876307080Ssephe net_vsc_pkt->data = ((uint8_t *)net_dev->rx_buf + 877307080Ssephe pkt->cp_rxbuf[i].rb_ofs); 878307080Ssephe net_vsc_pkt->tot_data_buf_len = pkt->cp_rxbuf[i].rb_len; 879250199Sgrehan 880307022Ssephe hv_rf_on_receive(net_dev, chan, net_vsc_pkt); 881285236Swhu if (net_vsc_pkt->status != nvsp_status_success) { 882285236Swhu status = nvsp_status_failure; 883285236Swhu } 884250199Sgrehan } 885285236Swhu 886250199Sgrehan /* 887285236Swhu * Moved completion call back here so that all received 888285236Swhu * messages (not just data messages) will trigger a response 889285236Swhu * message back to the host. 890250199Sgrehan */ 891307080Ssephe hv_nv_on_receive_completion(chan, pkt->cp_hdr.cph_xactid, status); 892250199Sgrehan} 893250199Sgrehan 894250199Sgrehan/* 895285236Swhu * Net VSC on receive completion 896285236Swhu * 897285236Swhu * Send a receive completion packet to RNDIS device (ie NetVsp) 898250199Sgrehan */ 899301918Ssephestatic void 900301918Ssephehv_nv_on_receive_completion(struct hv_vmbus_channel *chan, uint64_t tid, 901285236Swhu uint32_t status) 902250199Sgrehan{ 903250199Sgrehan nvsp_msg rx_comp_msg; 904250199Sgrehan int retries = 0; 905250199Sgrehan int ret = 0; 906250199Sgrehan 907250199Sgrehan rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete; 908250199Sgrehan 909250199Sgrehan /* Pass in the status */ 910250199Sgrehan rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = 911285236Swhu status; 912250199Sgrehan 913250199Sgrehanretry_send_cmplt: 914250199Sgrehan /* Send the completion */ 915307079Ssephe ret = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_COMP, 0, 916307079Ssephe &rx_comp_msg, sizeof(nvsp_msg), tid); 917250199Sgrehan if (ret == 0) { 918250199Sgrehan /* success */ 919250199Sgrehan /* no-op */ 920250199Sgrehan } else if (ret == EAGAIN) { 921250199Sgrehan /* no more room... wait a bit and attempt to retry 3 times */ 922250199Sgrehan retries++; 923250199Sgrehan 924250199Sgrehan if (retries < 4) { 925250199Sgrehan DELAY(100); 926250199Sgrehan goto retry_send_cmplt; 927250199Sgrehan } 928250199Sgrehan } 929250199Sgrehan} 930250199Sgrehan 931250199Sgrehan/* 932301943Ssephe * Net VSC receiving vRSS send table from VSP 933301943Ssephe */ 934301943Ssephestatic void 935307080Ssephehv_nv_send_table(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt) 936301943Ssephe{ 937301943Ssephe netvsc_dev *net_dev; 938307080Ssephe const nvsp_msg *nvsp_msg_pkt; 939301943Ssephe int i; 940307080Ssephe uint32_t count; 941307080Ssephe const uint32_t *table; 942301943Ssephe 943307022Ssephe net_dev = hv_nv_get_inbound_net_device(sc); 944301943Ssephe if (!net_dev) 945301943Ssephe return; 946301943Ssephe 947307080Ssephe nvsp_msg_pkt = VMBUS_CHANPKT_CONST_DATA(pkt); 948301943Ssephe 949301943Ssephe if (nvsp_msg_pkt->hdr.msg_type != 950301943Ssephe nvsp_msg5_type_send_indirection_table) { 951301943Ssephe printf("Netvsc: !Warning! receive msg type not " 952301943Ssephe "send_indirection_table. type = %d\n", 953301943Ssephe nvsp_msg_pkt->hdr.msg_type); 954301943Ssephe return; 955301943Ssephe } 956301943Ssephe 957301943Ssephe count = nvsp_msg_pkt->msgs.vers_5_msgs.send_table.count; 958301943Ssephe if (count != VRSS_SEND_TABLE_SIZE) { 959301943Ssephe printf("Netvsc: Received wrong send table size: %u\n", count); 960301943Ssephe return; 961301943Ssephe } 962301943Ssephe 963307080Ssephe table = (const uint32_t *) 964307080Ssephe ((const uint8_t *)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table + 965301943Ssephe nvsp_msg_pkt->msgs.vers_5_msgs.send_table.offset); 966301943Ssephe 967301943Ssephe for (i = 0; i < count; i++) 968301943Ssephe net_dev->vrss_send_table[i] = table[i]; 969301943Ssephe} 970301943Ssephe 971301943Ssephe/* 972250199Sgrehan * Net VSC on channel callback 973250199Sgrehan */ 974250199Sgrehanstatic void 975301912Ssephehv_nv_on_channel_callback(void *xchan) 976250199Sgrehan{ 977301912Ssephe struct hv_vmbus_channel *chan = xchan; 978307022Ssephe device_t dev = chan->ch_dev; 979307022Ssephe struct hn_softc *sc = device_get_softc(dev); 980250199Sgrehan netvsc_dev *net_dev; 981307080Ssephe void *buffer; 982285236Swhu int bufferlen = NETVSC_PACKET_SIZE; 983250199Sgrehan 984307022Ssephe net_dev = hv_nv_get_inbound_net_device(sc); 985285236Swhu if (net_dev == NULL) 986250199Sgrehan return; 987250199Sgrehan 988301918Ssephe buffer = chan->hv_chan_rdbuf; 989307080Ssephe do { 990307080Ssephe struct vmbus_chanpkt_hdr *pkt = buffer; 991307080Ssephe uint32_t bytes_rxed; 992307080Ssephe int ret; 993250199Sgrehan 994307080Ssephe bytes_rxed = bufferlen; 995307080Ssephe ret = vmbus_chan_recv_pkt(chan, pkt, &bytes_rxed); 996250199Sgrehan if (ret == 0) { 997250199Sgrehan if (bytes_rxed > 0) { 998307080Ssephe switch (pkt->cph_type) { 999307034Ssephe case VMBUS_CHANPKT_TYPE_COMP: 1000307022Ssephe hv_nv_on_send_completion(net_dev, chan, 1001307080Ssephe pkt); 1002250199Sgrehan break; 1003307034Ssephe case VMBUS_CHANPKT_TYPE_RXBUF: 1004307080Ssephe hv_nv_on_receive(net_dev, sc, chan, pkt); 1005250199Sgrehan break; 1006307034Ssephe case VMBUS_CHANPKT_TYPE_INBAND: 1007307080Ssephe hv_nv_send_table(sc, pkt); 1008301943Ssephe break; 1009250199Sgrehan default: 1010285236Swhu device_printf(dev, 1011307080Ssephe "unknown chan pkt %u\n", 1012307080Ssephe pkt->cph_type); 1013250199Sgrehan break; 1014250199Sgrehan } 1015250199Sgrehan } 1016250199Sgrehan } else if (ret == ENOBUFS) { 1017250199Sgrehan /* Handle large packet */ 1018285236Swhu if (bufferlen > NETVSC_PACKET_SIZE) { 1019285236Swhu free(buffer, M_NETVSC); 1020285236Swhu buffer = NULL; 1021285236Swhu } 1022285236Swhu 1023285236Swhu /* alloc new buffer */ 1024285236Swhu buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT); 1025250199Sgrehan if (buffer == NULL) { 1026285236Swhu device_printf(dev, 1027285236Swhu "hv_cb malloc buffer failed, len=%u\n", 1028285236Swhu bytes_rxed); 1029285236Swhu bufferlen = 0; 1030250199Sgrehan break; 1031250199Sgrehan } 1032250199Sgrehan bufferlen = bytes_rxed; 1033307080Ssephe } else { 1034307080Ssephe /* No more packets */ 1035307080Ssephe break; 1036250199Sgrehan } 1037250199Sgrehan } while (1); 1038250199Sgrehan 1039285236Swhu if (bufferlen > NETVSC_PACKET_SIZE) 1040285236Swhu free(buffer, M_NETVSC); 1041295948Ssephe 1042301912Ssephe hv_rf_channel_rollup(chan); 1043250199Sgrehan} 1044