hn_nvs.c revision 285236
1250199Sgrehan/*- 2250199Sgrehan * Copyright (c) 2009-2012 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 285236 2015-07-07 04:15:22Z whu $ 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 51285236SwhuMALLOC_DEFINE(M_NETVSC, "netvsc", "Hyper-V netvsc driver"); 52250199Sgrehan 53250199Sgrehan/* 54250199Sgrehan * Forward declarations 55250199Sgrehan */ 56250199Sgrehanstatic void hv_nv_on_channel_callback(void *context); 57250199Sgrehanstatic int hv_nv_init_send_buffer_with_net_vsp(struct hv_device *device); 58250199Sgrehanstatic int hv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device); 59250199Sgrehanstatic int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); 60250199Sgrehanstatic int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev); 61250199Sgrehanstatic int hv_nv_connect_to_vsp(struct hv_device *device); 62285236Swhustatic void hv_nv_on_send_completion(netvsc_dev *net_dev, 63285236Swhu struct hv_device *device, hv_vm_packet_descriptor *pkt); 64285236Swhustatic void hv_nv_on_receive(netvsc_dev *net_dev, 65285236Swhu struct hv_device *device, hv_vm_packet_descriptor *pkt); 66250199Sgrehan 67250199Sgrehan/* 68250199Sgrehan * 69250199Sgrehan */ 70250199Sgrehanstatic inline netvsc_dev * 71250199Sgrehanhv_nv_alloc_net_device(struct hv_device *device) 72250199Sgrehan{ 73250199Sgrehan netvsc_dev *net_dev; 74250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 75250199Sgrehan 76285236Swhu net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_NOWAIT | M_ZERO); 77250199Sgrehan if (net_dev == NULL) { 78250199Sgrehan return (NULL); 79250199Sgrehan } 80250199Sgrehan 81250199Sgrehan net_dev->dev = device; 82250199Sgrehan net_dev->destroy = FALSE; 83250199Sgrehan sc->net_dev = net_dev; 84250199Sgrehan 85250199Sgrehan return (net_dev); 86250199Sgrehan} 87250199Sgrehan 88250199Sgrehan/* 89250199Sgrehan * 90250199Sgrehan */ 91250199Sgrehanstatic inline netvsc_dev * 92250199Sgrehanhv_nv_get_outbound_net_device(struct hv_device *device) 93250199Sgrehan{ 94250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 95250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 96250199Sgrehan 97250199Sgrehan if ((net_dev != NULL) && net_dev->destroy) { 98250199Sgrehan return (NULL); 99250199Sgrehan } 100250199Sgrehan 101250199Sgrehan return (net_dev); 102250199Sgrehan} 103250199Sgrehan 104250199Sgrehan/* 105250199Sgrehan * 106250199Sgrehan */ 107250199Sgrehanstatic inline netvsc_dev * 108250199Sgrehanhv_nv_get_inbound_net_device(struct hv_device *device) 109250199Sgrehan{ 110250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 111250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 112250199Sgrehan 113250199Sgrehan if (net_dev == NULL) { 114250199Sgrehan return (net_dev); 115250199Sgrehan } 116250199Sgrehan /* 117250199Sgrehan * When the device is being destroyed; we only 118250199Sgrehan * permit incoming packets if and only if there 119250199Sgrehan * are outstanding sends. 120250199Sgrehan */ 121250199Sgrehan if (net_dev->destroy && net_dev->num_outstanding_sends == 0) { 122250199Sgrehan return (NULL); 123250199Sgrehan } 124250199Sgrehan 125250199Sgrehan return (net_dev); 126250199Sgrehan} 127250199Sgrehan 128285236Swhuint 129285236Swhuhv_nv_get_next_send_section(netvsc_dev *net_dev) 130285236Swhu{ 131285236Swhu unsigned long bitsmap_words = net_dev->bitsmap_words; 132285236Swhu unsigned long *bitsmap = net_dev->send_section_bitsmap; 133285236Swhu unsigned long idx; 134285236Swhu int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; 135285236Swhu int i; 136285236Swhu 137285236Swhu for (i = 0; i < bitsmap_words; i++) { 138285236Swhu idx = ffs(~bitsmap[i]); 139285236Swhu if (0 == idx) 140285236Swhu continue; 141285236Swhu 142285236Swhu idx--; 143285236Swhu if (i * BITS_PER_LONG + idx >= net_dev->send_section_count) 144285236Swhu return (ret); 145285236Swhu 146285236Swhu if (synch_test_and_set_bit(idx, &bitsmap[i])) 147285236Swhu continue; 148285236Swhu 149285236Swhu ret = i * BITS_PER_LONG + idx; 150285236Swhu break; 151285236Swhu } 152285236Swhu 153285236Swhu return (ret); 154285236Swhu} 155285236Swhu 156250199Sgrehan/* 157250199Sgrehan * Net VSC initialize receive buffer with net VSP 158250199Sgrehan * 159250199Sgrehan * Net VSP: Network virtual services client, also known as the 160250199Sgrehan * Hyper-V extensible switch and the synthetic data path. 161250199Sgrehan */ 162250199Sgrehanstatic int 163250199Sgrehanhv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device) 164250199Sgrehan{ 165250199Sgrehan netvsc_dev *net_dev; 166250199Sgrehan nvsp_msg *init_pkt; 167250199Sgrehan int ret = 0; 168250199Sgrehan 169250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 170250199Sgrehan if (!net_dev) { 171250199Sgrehan return (ENODEV); 172250199Sgrehan } 173250199Sgrehan 174285236Swhu net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_NETVSC, 175250199Sgrehan M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); 176250199Sgrehan 177250199Sgrehan /* 178250199Sgrehan * Establish the GPADL handle for this buffer on this channel. 179250199Sgrehan * Note: This call uses the vmbus connection rather than the 180250199Sgrehan * channel to establish the gpadl handle. 181250199Sgrehan * GPADL: Guest physical address descriptor list. 182250199Sgrehan */ 183250199Sgrehan ret = hv_vmbus_channel_establish_gpadl( 184250199Sgrehan device->channel, net_dev->rx_buf, 185250199Sgrehan net_dev->rx_buf_size, &net_dev->rx_buf_gpadl_handle); 186250199Sgrehan if (ret != 0) { 187250199Sgrehan goto cleanup; 188250199Sgrehan } 189250199Sgrehan 190250199Sgrehan /* sema_wait(&ext->channel_init_sema); KYS CHECK */ 191250199Sgrehan 192250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 193250199Sgrehan init_pkt = &net_dev->channel_init_packet; 194250199Sgrehan 195250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 196250199Sgrehan 197250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf; 198250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 199250199Sgrehan net_dev->rx_buf_gpadl_handle; 200250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 201250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 202250199Sgrehan 203250199Sgrehan /* Send the gpadl notification request */ 204250199Sgrehan 205250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 206266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 207250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 208250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 209250199Sgrehan if (ret != 0) { 210250199Sgrehan goto cleanup; 211250199Sgrehan } 212250199Sgrehan 213250199Sgrehan sema_wait(&net_dev->channel_init_sema); 214250199Sgrehan 215250199Sgrehan /* Check the response */ 216250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status 217250199Sgrehan != nvsp_status_success) { 218250199Sgrehan ret = EINVAL; 219250199Sgrehan goto cleanup; 220250199Sgrehan } 221250199Sgrehan 222250199Sgrehan net_dev->rx_section_count = 223250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; 224250199Sgrehan 225250199Sgrehan net_dev->rx_sections = malloc(net_dev->rx_section_count * 226285236Swhu sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_NOWAIT); 227250199Sgrehan if (net_dev->rx_sections == NULL) { 228250199Sgrehan ret = EINVAL; 229250199Sgrehan goto cleanup; 230250199Sgrehan } 231250199Sgrehan memcpy(net_dev->rx_sections, 232250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections, 233250199Sgrehan net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section)); 234250199Sgrehan 235250199Sgrehan 236250199Sgrehan /* 237250199Sgrehan * For first release, there should only be 1 section that represents 238250199Sgrehan * the entire receive buffer 239250199Sgrehan */ 240250199Sgrehan if (net_dev->rx_section_count != 1 241250199Sgrehan || net_dev->rx_sections->offset != 0) { 242250199Sgrehan ret = EINVAL; 243250199Sgrehan goto cleanup; 244250199Sgrehan } 245250199Sgrehan 246250199Sgrehan goto exit; 247250199Sgrehan 248250199Sgrehancleanup: 249250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 250250199Sgrehan 251250199Sgrehanexit: 252250199Sgrehan return (ret); 253250199Sgrehan} 254250199Sgrehan 255250199Sgrehan/* 256250199Sgrehan * Net VSC initialize send buffer with net VSP 257250199Sgrehan */ 258250199Sgrehanstatic int 259250199Sgrehanhv_nv_init_send_buffer_with_net_vsp(struct hv_device *device) 260250199Sgrehan{ 261250199Sgrehan netvsc_dev *net_dev; 262250199Sgrehan nvsp_msg *init_pkt; 263250199Sgrehan int ret = 0; 264250199Sgrehan 265250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 266250199Sgrehan if (!net_dev) { 267250199Sgrehan return (ENODEV); 268250199Sgrehan } 269250199Sgrehan 270285236Swhu net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_NETVSC, 271250199Sgrehan M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); 272250199Sgrehan if (net_dev->send_buf == NULL) { 273250199Sgrehan ret = ENOMEM; 274250199Sgrehan goto cleanup; 275250199Sgrehan } 276250199Sgrehan 277250199Sgrehan /* 278250199Sgrehan * Establish the gpadl handle for this buffer on this channel. 279250199Sgrehan * Note: This call uses the vmbus connection rather than the 280250199Sgrehan * channel to establish the gpadl handle. 281250199Sgrehan */ 282250199Sgrehan ret = hv_vmbus_channel_establish_gpadl(device->channel, 283285236Swhu net_dev->send_buf, net_dev->send_buf_size, 284250199Sgrehan &net_dev->send_buf_gpadl_handle); 285250199Sgrehan if (ret != 0) { 286250199Sgrehan goto cleanup; 287250199Sgrehan } 288250199Sgrehan 289250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 290250199Sgrehan 291250199Sgrehan init_pkt = &net_dev->channel_init_packet; 292250199Sgrehan 293250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 294250199Sgrehan 295250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf; 296250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 297250199Sgrehan net_dev->send_buf_gpadl_handle; 298250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 299250199Sgrehan NETVSC_SEND_BUFFER_ID; 300250199Sgrehan 301250199Sgrehan /* Send the gpadl notification request */ 302250199Sgrehan 303250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 304285236Swhu sizeof(nvsp_msg), (uint64_t)init_pkt, 305250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 306250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 307250199Sgrehan if (ret != 0) { 308250199Sgrehan goto cleanup; 309250199Sgrehan } 310250199Sgrehan 311250199Sgrehan sema_wait(&net_dev->channel_init_sema); 312250199Sgrehan 313250199Sgrehan /* Check the response */ 314250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status 315250199Sgrehan != nvsp_status_success) { 316250199Sgrehan ret = EINVAL; 317250199Sgrehan goto cleanup; 318250199Sgrehan } 319250199Sgrehan 320250199Sgrehan net_dev->send_section_size = 321250199Sgrehan init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; 322285236Swhu net_dev->send_section_count = 323285236Swhu net_dev->send_buf_size / net_dev->send_section_size; 324285236Swhu net_dev->bitsmap_words = howmany(net_dev->send_section_count, 325285236Swhu BITS_PER_LONG); 326285236Swhu net_dev->send_section_bitsmap = 327285236Swhu malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC, 328285236Swhu M_NOWAIT | M_ZERO); 329285236Swhu if (NULL == net_dev->send_section_bitsmap) { 330285236Swhu ret = ENOMEM; 331285236Swhu goto cleanup; 332285236Swhu } 333250199Sgrehan 334250199Sgrehan goto exit; 335250199Sgrehan 336250199Sgrehancleanup: 337250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 338250199Sgrehan 339250199Sgrehanexit: 340250199Sgrehan return (ret); 341250199Sgrehan} 342250199Sgrehan 343250199Sgrehan/* 344250199Sgrehan * Net VSC destroy receive buffer 345250199Sgrehan */ 346250199Sgrehanstatic int 347250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev) 348250199Sgrehan{ 349250199Sgrehan nvsp_msg *revoke_pkt; 350250199Sgrehan int ret = 0; 351250199Sgrehan 352250199Sgrehan /* 353250199Sgrehan * If we got a section count, it means we received a 354250199Sgrehan * send_rx_buf_complete msg 355250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 356250199Sgrehan * we need to send a revoke msg here 357250199Sgrehan */ 358250199Sgrehan if (net_dev->rx_section_count) { 359250199Sgrehan /* Send the revoke receive buffer */ 360250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 361250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 362250199Sgrehan 363250199Sgrehan revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf; 364250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id = 365250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 366250199Sgrehan 367250199Sgrehan ret = hv_vmbus_channel_send_packet(net_dev->dev->channel, 368250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 369266794Smarius (uint64_t)(uintptr_t)revoke_pkt, 370250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 371250199Sgrehan 372250199Sgrehan /* 373250199Sgrehan * If we failed here, we might as well return and have a leak 374250199Sgrehan * rather than continue and a bugchk 375250199Sgrehan */ 376250199Sgrehan if (ret != 0) { 377250199Sgrehan return (ret); 378250199Sgrehan } 379250199Sgrehan } 380250199Sgrehan 381250199Sgrehan /* Tear down the gpadl on the vsp end */ 382250199Sgrehan if (net_dev->rx_buf_gpadl_handle) { 383250199Sgrehan ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel, 384250199Sgrehan net_dev->rx_buf_gpadl_handle); 385250199Sgrehan /* 386250199Sgrehan * If we failed here, we might as well return and have a leak 387250199Sgrehan * rather than continue and a bugchk 388250199Sgrehan */ 389250199Sgrehan if (ret != 0) { 390250199Sgrehan return (ret); 391250199Sgrehan } 392250199Sgrehan net_dev->rx_buf_gpadl_handle = 0; 393250199Sgrehan } 394250199Sgrehan 395250199Sgrehan if (net_dev->rx_buf) { 396250199Sgrehan /* Free up the receive buffer */ 397285236Swhu contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_NETVSC); 398250199Sgrehan net_dev->rx_buf = NULL; 399250199Sgrehan } 400250199Sgrehan 401250199Sgrehan if (net_dev->rx_sections) { 402285236Swhu free(net_dev->rx_sections, M_NETVSC); 403250199Sgrehan net_dev->rx_sections = NULL; 404250199Sgrehan net_dev->rx_section_count = 0; 405250199Sgrehan } 406250199Sgrehan 407250199Sgrehan return (ret); 408250199Sgrehan} 409250199Sgrehan 410250199Sgrehan/* 411250199Sgrehan * Net VSC destroy send buffer 412250199Sgrehan */ 413250199Sgrehanstatic int 414250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev) 415250199Sgrehan{ 416250199Sgrehan nvsp_msg *revoke_pkt; 417250199Sgrehan int ret = 0; 418250199Sgrehan 419250199Sgrehan /* 420250199Sgrehan * If we got a section count, it means we received a 421250199Sgrehan * send_rx_buf_complete msg 422250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 423250199Sgrehan * we need to send a revoke msg here 424250199Sgrehan */ 425250199Sgrehan if (net_dev->send_section_size) { 426250199Sgrehan /* Send the revoke send buffer */ 427250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 428250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 429250199Sgrehan 430250199Sgrehan revoke_pkt->hdr.msg_type = 431250199Sgrehan nvsp_msg_1_type_revoke_send_buf; 432250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id = 433250199Sgrehan NETVSC_SEND_BUFFER_ID; 434250199Sgrehan 435250199Sgrehan ret = hv_vmbus_channel_send_packet(net_dev->dev->channel, 436250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 437266794Smarius (uint64_t)(uintptr_t)revoke_pkt, 438250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 439250199Sgrehan /* 440250199Sgrehan * If we failed here, we might as well return and have a leak 441250199Sgrehan * rather than continue and a bugchk 442250199Sgrehan */ 443250199Sgrehan if (ret != 0) { 444250199Sgrehan return (ret); 445250199Sgrehan } 446250199Sgrehan } 447250199Sgrehan 448250199Sgrehan /* Tear down the gpadl on the vsp end */ 449250199Sgrehan if (net_dev->send_buf_gpadl_handle) { 450250199Sgrehan ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel, 451250199Sgrehan net_dev->send_buf_gpadl_handle); 452250199Sgrehan 453250199Sgrehan /* 454250199Sgrehan * If we failed here, we might as well return and have a leak 455250199Sgrehan * rather than continue and a bugchk 456250199Sgrehan */ 457250199Sgrehan if (ret != 0) { 458250199Sgrehan return (ret); 459250199Sgrehan } 460250199Sgrehan net_dev->send_buf_gpadl_handle = 0; 461250199Sgrehan } 462250199Sgrehan 463250199Sgrehan if (net_dev->send_buf) { 464250199Sgrehan /* Free up the receive buffer */ 465285236Swhu contigfree(net_dev->send_buf, net_dev->send_buf_size, M_NETVSC); 466250199Sgrehan net_dev->send_buf = NULL; 467250199Sgrehan } 468250199Sgrehan 469285236Swhu if (net_dev->send_section_bitsmap) { 470285236Swhu free(net_dev->send_section_bitsmap, M_NETVSC); 471285236Swhu } 472285236Swhu 473250199Sgrehan return (ret); 474250199Sgrehan} 475250199Sgrehan 476250199Sgrehan 477250199Sgrehan/* 478250199Sgrehan * Attempt to negotiate the caller-specified NVSP version 479250199Sgrehan * 480250199Sgrehan * For NVSP v2, Server 2008 R2 does not set 481250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers 482250199Sgrehan * to the negotiated version, so we cannot rely on that. 483250199Sgrehan */ 484250199Sgrehanstatic int 485250199Sgrehanhv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev, 486285236Swhu uint32_t nvsp_ver) 487250199Sgrehan{ 488250199Sgrehan nvsp_msg *init_pkt; 489250199Sgrehan int ret; 490250199Sgrehan 491250199Sgrehan init_pkt = &net_dev->channel_init_packet; 492250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 493250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_type_init; 494250199Sgrehan 495250199Sgrehan /* 496250199Sgrehan * Specify parameter as the only acceptable protocol version 497250199Sgrehan */ 498250199Sgrehan init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver; 499250199Sgrehan init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver; 500250199Sgrehan 501250199Sgrehan /* Send the init request */ 502250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 503266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 504250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 505250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 506250199Sgrehan if (ret != 0) 507250199Sgrehan return (-1); 508250199Sgrehan 509250199Sgrehan sema_wait(&net_dev->channel_init_sema); 510250199Sgrehan 511250199Sgrehan if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success) 512250199Sgrehan return (EINVAL); 513250199Sgrehan 514250199Sgrehan return (0); 515250199Sgrehan} 516250199Sgrehan 517250199Sgrehan/* 518250199Sgrehan * Send NDIS version 2 config packet containing MTU. 519250199Sgrehan * 520250199Sgrehan * Not valid for NDIS version 1. 521250199Sgrehan */ 522250199Sgrehanstatic int 523250199Sgrehanhv_nv_send_ndis_config(struct hv_device *device, uint32_t mtu) 524250199Sgrehan{ 525250199Sgrehan netvsc_dev *net_dev; 526250199Sgrehan nvsp_msg *init_pkt; 527250199Sgrehan int ret; 528250199Sgrehan 529250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 530250199Sgrehan if (!net_dev) 531250199Sgrehan return (-ENODEV); 532250199Sgrehan 533250199Sgrehan /* 534250199Sgrehan * Set up configuration packet, write MTU 535250199Sgrehan * Indicate we are capable of handling VLAN tags 536250199Sgrehan */ 537250199Sgrehan init_pkt = &net_dev->channel_init_packet; 538250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 539250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config; 540250199Sgrehan init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu; 541250199Sgrehan init_pkt-> 542250199Sgrehan msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q 543250199Sgrehan = 1; 544250199Sgrehan 545250199Sgrehan /* Send the configuration packet */ 546250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 547266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 548250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 549250199Sgrehan if (ret != 0) 550250199Sgrehan return (-EINVAL); 551250199Sgrehan 552250199Sgrehan return (0); 553250199Sgrehan} 554250199Sgrehan 555250199Sgrehan/* 556250199Sgrehan * Net VSC connect to VSP 557250199Sgrehan */ 558250199Sgrehanstatic int 559250199Sgrehanhv_nv_connect_to_vsp(struct hv_device *device) 560250199Sgrehan{ 561250199Sgrehan netvsc_dev *net_dev; 562250199Sgrehan nvsp_msg *init_pkt; 563250199Sgrehan uint32_t ndis_version; 564285236Swhu uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1, 565285236Swhu NVSP_PROTOCOL_VERSION_2, 566285236Swhu NVSP_PROTOCOL_VERSION_4, 567285236Swhu NVSP_PROTOCOL_VERSION_5 }; 568285236Swhu int i; 569285236Swhu int protocol_number = nitems(protocol_list); 570250199Sgrehan int ret = 0; 571250199Sgrehan device_t dev = device->device; 572250199Sgrehan hn_softc_t *sc = device_get_softc(dev); 573250199Sgrehan struct ifnet *ifp = sc->arpcom.ac_ifp; 574250199Sgrehan 575250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 576250199Sgrehan if (!net_dev) { 577250199Sgrehan return (ENODEV); 578250199Sgrehan } 579250199Sgrehan 580250199Sgrehan /* 581285236Swhu * Negotiate the NVSP version. Try the latest NVSP first. 582250199Sgrehan */ 583285236Swhu for (i = protocol_number - 1; i >= 0; i--) { 584285236Swhu if (hv_nv_negotiate_nvsp_protocol(device, net_dev, 585285236Swhu protocol_list[i]) == 0) { 586285236Swhu net_dev->nvsp_version = protocol_list[i]; 587285236Swhu if (bootverbose) 588285236Swhu device_printf(dev, "Netvsc: got version 0x%x\n", 589285236Swhu net_dev->nvsp_version); 590285236Swhu break; 591250199Sgrehan } 592250199Sgrehan } 593250199Sgrehan 594285236Swhu if (i < 0) { 595285236Swhu if (bootverbose) 596285236Swhu device_printf(dev, "failed to negotiate a valid " 597285236Swhu "protocol.\n"); 598285236Swhu return (EPROTO); 599285236Swhu } 600285236Swhu 601250199Sgrehan /* 602250199Sgrehan * Set the MTU if supported by this NVSP protocol version 603250199Sgrehan * This needs to be right after the NVSP init message per Haiyang 604250199Sgrehan */ 605285236Swhu if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) 606250199Sgrehan ret = hv_nv_send_ndis_config(device, ifp->if_mtu); 607250199Sgrehan 608250199Sgrehan /* 609250199Sgrehan * Send the NDIS version 610250199Sgrehan */ 611250199Sgrehan init_pkt = &net_dev->channel_init_packet; 612250199Sgrehan 613250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 614250199Sgrehan 615285236Swhu if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) { 616285236Swhu ndis_version = NDIS_VERSION_6_1; 617285236Swhu } else { 618285236Swhu ndis_version = NDIS_VERSION_6_30; 619285236Swhu } 620250199Sgrehan 621250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; 622250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = 623250199Sgrehan (ndis_version & 0xFFFF0000) >> 16; 624250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers = 625250199Sgrehan ndis_version & 0xFFFF; 626250199Sgrehan 627250199Sgrehan /* Send the init request */ 628250199Sgrehan 629250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 630266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 631250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 632250199Sgrehan if (ret != 0) { 633250199Sgrehan goto cleanup; 634250199Sgrehan } 635250199Sgrehan /* 636250199Sgrehan * TODO: BUGBUG - We have to wait for the above msg since the netvsp 637250199Sgrehan * uses KMCL which acknowledges packet (completion packet) 638250199Sgrehan * since our Vmbus always set the 639250199Sgrehan * HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag 640250199Sgrehan */ 641250199Sgrehan /* sema_wait(&NetVscChannel->channel_init_sema); */ 642250199Sgrehan 643250199Sgrehan /* Post the big receive buffer to NetVSP */ 644250199Sgrehan ret = hv_nv_init_rx_buffer_with_net_vsp(device); 645250199Sgrehan if (ret == 0) 646250199Sgrehan ret = hv_nv_init_send_buffer_with_net_vsp(device); 647250199Sgrehan 648250199Sgrehancleanup: 649250199Sgrehan return (ret); 650250199Sgrehan} 651250199Sgrehan 652250199Sgrehan/* 653250199Sgrehan * Net VSC disconnect from VSP 654250199Sgrehan */ 655250199Sgrehanstatic void 656250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev) 657250199Sgrehan{ 658250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 659250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 660250199Sgrehan} 661250199Sgrehan 662250199Sgrehan/* 663250199Sgrehan * Net VSC on device add 664250199Sgrehan * 665250199Sgrehan * Callback when the device belonging to this driver is added 666250199Sgrehan */ 667250199Sgrehannetvsc_dev * 668250199Sgrehanhv_nv_on_device_add(struct hv_device *device, void *additional_info) 669250199Sgrehan{ 670250199Sgrehan netvsc_dev *net_dev; 671285236Swhu int ret = 0; 672250199Sgrehan 673250199Sgrehan net_dev = hv_nv_alloc_net_device(device); 674250199Sgrehan if (!net_dev) 675250199Sgrehan goto cleanup; 676250199Sgrehan 677250199Sgrehan /* Initialize the NetVSC channel extension */ 678250199Sgrehan net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; 679250199Sgrehan 680250199Sgrehan net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; 681250199Sgrehan 682250199Sgrehan sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); 683250199Sgrehan 684250199Sgrehan /* 685250199Sgrehan * Open the channel 686250199Sgrehan */ 687250199Sgrehan ret = hv_vmbus_channel_open(device->channel, 688250199Sgrehan NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE, 689250199Sgrehan NULL, 0, hv_nv_on_channel_callback, device); 690250199Sgrehan if (ret != 0) 691250199Sgrehan goto cleanup; 692250199Sgrehan 693250199Sgrehan /* 694250199Sgrehan * Connect with the NetVsp 695250199Sgrehan */ 696250199Sgrehan ret = hv_nv_connect_to_vsp(device); 697250199Sgrehan if (ret != 0) 698250199Sgrehan goto close; 699250199Sgrehan 700250199Sgrehan return (net_dev); 701250199Sgrehan 702250199Sgrehanclose: 703250199Sgrehan /* Now, we can close the channel safely */ 704250199Sgrehan 705250199Sgrehan hv_vmbus_channel_close(device->channel); 706250199Sgrehan 707250199Sgrehancleanup: 708250199Sgrehan /* 709250199Sgrehan * Free the packet buffers on the netvsc device packet queue. 710250199Sgrehan * Release other resources. 711250199Sgrehan */ 712250199Sgrehan if (net_dev) { 713250199Sgrehan sema_destroy(&net_dev->channel_init_sema); 714285236Swhu free(net_dev, M_NETVSC); 715250199Sgrehan } 716250199Sgrehan 717250199Sgrehan return (NULL); 718250199Sgrehan} 719250199Sgrehan 720250199Sgrehan/* 721250199Sgrehan * Net VSC on device remove 722250199Sgrehan */ 723250199Sgrehanint 724250199Sgrehanhv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel) 725250199Sgrehan{ 726250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 727250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 728250199Sgrehan 729250199Sgrehan /* Stop outbound traffic ie sends and receives completions */ 730250199Sgrehan mtx_lock(&device->channel->inbound_lock); 731250199Sgrehan net_dev->destroy = TRUE; 732250199Sgrehan mtx_unlock(&device->channel->inbound_lock); 733250199Sgrehan 734250199Sgrehan /* Wait for all send completions */ 735250199Sgrehan while (net_dev->num_outstanding_sends) { 736250199Sgrehan DELAY(100); 737250199Sgrehan } 738250199Sgrehan 739250199Sgrehan hv_nv_disconnect_from_vsp(net_dev); 740250199Sgrehan 741250199Sgrehan /* At this point, no one should be accessing net_dev except in here */ 742250199Sgrehan 743250199Sgrehan /* Now, we can close the channel safely */ 744250199Sgrehan 745250199Sgrehan if (!destroy_channel) { 746250199Sgrehan device->channel->state = 747250199Sgrehan HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE; 748250199Sgrehan } 749250199Sgrehan 750250199Sgrehan hv_vmbus_channel_close(device->channel); 751250199Sgrehan 752250199Sgrehan sema_destroy(&net_dev->channel_init_sema); 753285236Swhu free(net_dev, M_NETVSC); 754250199Sgrehan 755250199Sgrehan return (0); 756250199Sgrehan} 757250199Sgrehan 758250199Sgrehan/* 759250199Sgrehan * Net VSC on send completion 760250199Sgrehan */ 761285236Swhustatic void 762285236Swhuhv_nv_on_send_completion(netvsc_dev *net_dev, 763285236Swhu struct hv_device *device, hv_vm_packet_descriptor *pkt) 764250199Sgrehan{ 765250199Sgrehan nvsp_msg *nvsp_msg_pkt; 766250199Sgrehan netvsc_packet *net_vsc_pkt; 767250199Sgrehan 768250199Sgrehan nvsp_msg_pkt = 769250199Sgrehan (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); 770250199Sgrehan 771250199Sgrehan if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete 772250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 773250199Sgrehan == nvsp_msg_1_type_send_rx_buf_complete 774250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 775250199Sgrehan == nvsp_msg_1_type_send_send_buf_complete) { 776250199Sgrehan /* Copy the response back */ 777250199Sgrehan memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, 778285236Swhu sizeof(nvsp_msg)); 779250199Sgrehan sema_post(&net_dev->channel_init_sema); 780250199Sgrehan } else if (nvsp_msg_pkt->hdr.msg_type == 781285236Swhu nvsp_msg_1_type_send_rndis_pkt_complete) { 782250199Sgrehan /* Get the send context */ 783250199Sgrehan net_vsc_pkt = 784250199Sgrehan (netvsc_packet *)(unsigned long)pkt->transaction_id; 785285236Swhu if (NULL != net_vsc_pkt) { 786285236Swhu if (net_vsc_pkt->send_buf_section_idx != 787285236Swhu NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { 788285236Swhu synch_change_bit(net_vsc_pkt->send_buf_section_idx, 789285236Swhu net_dev->send_section_bitsmap); 790285236Swhu } 791285236Swhu 792285236Swhu /* Notify the layer above us */ 793285236Swhu net_vsc_pkt->compl.send.on_send_completion( 794285236Swhu net_vsc_pkt->compl.send.send_completion_context); 795250199Sgrehan 796285236Swhu } 797250199Sgrehan 798250199Sgrehan atomic_subtract_int(&net_dev->num_outstanding_sends, 1); 799250199Sgrehan } 800250199Sgrehan} 801250199Sgrehan 802250199Sgrehan/* 803250199Sgrehan * Net VSC on send 804250199Sgrehan * Sends a packet on the specified Hyper-V device. 805250199Sgrehan * Returns 0 on success, non-zero on failure. 806250199Sgrehan */ 807250199Sgrehanint 808250199Sgrehanhv_nv_on_send(struct hv_device *device, netvsc_packet *pkt) 809250199Sgrehan{ 810250199Sgrehan netvsc_dev *net_dev; 811250199Sgrehan nvsp_msg send_msg; 812250199Sgrehan int ret; 813250199Sgrehan 814250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 815250199Sgrehan if (!net_dev) 816250199Sgrehan return (ENODEV); 817250199Sgrehan 818250199Sgrehan send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt; 819250199Sgrehan if (pkt->is_data_pkt) { 820250199Sgrehan /* 0 is RMC_DATA */ 821250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0; 822250199Sgrehan } else { 823250199Sgrehan /* 1 is RMC_CONTROL */ 824250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; 825250199Sgrehan } 826250199Sgrehan 827250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = 828285236Swhu pkt->send_buf_section_idx; 829285236Swhu send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 830285236Swhu pkt->send_buf_section_size; 831250199Sgrehan 832250199Sgrehan if (pkt->page_buf_count) { 833250199Sgrehan ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel, 834250199Sgrehan pkt->page_buffers, pkt->page_buf_count, 835266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt); 836250199Sgrehan } else { 837250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, 838266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt, 839250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 840250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 841250199Sgrehan } 842250199Sgrehan 843250199Sgrehan /* Record outstanding send only if send_packet() succeeded */ 844250199Sgrehan if (ret == 0) 845250199Sgrehan atomic_add_int(&net_dev->num_outstanding_sends, 1); 846250199Sgrehan 847250199Sgrehan return (ret); 848250199Sgrehan} 849250199Sgrehan 850250199Sgrehan/* 851250199Sgrehan * Net VSC on receive 852250199Sgrehan * 853250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively 854250199Sgrehan * with virtual addresses. 855250199Sgrehan */ 856285236Swhustatic void 857285236Swhuhv_nv_on_receive(netvsc_dev *net_dev, struct hv_device *device, 858285236Swhu hv_vm_packet_descriptor *pkt) 859250199Sgrehan{ 860250199Sgrehan hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; 861250199Sgrehan nvsp_msg *nvsp_msg_pkt; 862285236Swhu netvsc_packet vsc_pkt; 863285236Swhu netvsc_packet *net_vsc_pkt = &vsc_pkt; 864285236Swhu device_t dev = device->device; 865250199Sgrehan int count = 0; 866250199Sgrehan int i = 0; 867285236Swhu int status = nvsp_status_success; 868250199Sgrehan 869250199Sgrehan /* 870250199Sgrehan * All inbound packets other than send completion should be 871250199Sgrehan * xfer page packet. 872250199Sgrehan */ 873285236Swhu if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) { 874285236Swhu device_printf(dev, "packet type %d is invalid!\n", pkt->type); 875250199Sgrehan return; 876285236Swhu } 877250199Sgrehan 878250199Sgrehan nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt 879250199Sgrehan + (pkt->data_offset8 << 3)); 880250199Sgrehan 881250199Sgrehan /* Make sure this is a valid nvsp packet */ 882285236Swhu if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) { 883285236Swhu device_printf(dev, "packet hdr type %d is invalid!\n", 884285236Swhu pkt->type); 885250199Sgrehan return; 886285236Swhu } 887250199Sgrehan 888250199Sgrehan vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt; 889250199Sgrehan 890285236Swhu if (vm_xfer_page_pkt->transfer_page_set_id != 891285236Swhu NETVSC_RECEIVE_BUFFER_ID) { 892285236Swhu device_printf(dev, "transfer_page_set_id %d is invalid!\n", 893285236Swhu vm_xfer_page_pkt->transfer_page_set_id); 894250199Sgrehan return; 895250199Sgrehan } 896250199Sgrehan 897285236Swhu count = vm_xfer_page_pkt->range_count; 898285236Swhu net_vsc_pkt->device = device; 899250199Sgrehan 900285236Swhu /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 901285236Swhu for (i = 0; i < count; i++) { 902285236Swhu net_vsc_pkt->status = nvsp_status_success; 903285236Swhu net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf + 904285236Swhu vm_xfer_page_pkt->ranges[i].byte_offset); 905285236Swhu net_vsc_pkt->tot_data_buf_len = 906285236Swhu vm_xfer_page_pkt->ranges[i].byte_count; 907250199Sgrehan 908285236Swhu hv_rf_on_receive(net_dev, device, net_vsc_pkt); 909285236Swhu if (net_vsc_pkt->status != nvsp_status_success) { 910285236Swhu status = nvsp_status_failure; 911285236Swhu } 912250199Sgrehan } 913285236Swhu 914250199Sgrehan /* 915285236Swhu * Moved completion call back here so that all received 916285236Swhu * messages (not just data messages) will trigger a response 917285236Swhu * message back to the host. 918250199Sgrehan */ 919285236Swhu hv_nv_on_receive_completion(device, vm_xfer_page_pkt->d.transaction_id, 920285236Swhu status); 921250199Sgrehan} 922250199Sgrehan 923250199Sgrehan/* 924285236Swhu * Net VSC on receive completion 925285236Swhu * 926285236Swhu * Send a receive completion packet to RNDIS device (ie NetVsp) 927250199Sgrehan */ 928285236Swhuvoid 929285236Swhuhv_nv_on_receive_completion(struct hv_device *device, uint64_t tid, 930285236Swhu uint32_t status) 931250199Sgrehan{ 932250199Sgrehan nvsp_msg rx_comp_msg; 933250199Sgrehan int retries = 0; 934250199Sgrehan int ret = 0; 935250199Sgrehan 936250199Sgrehan rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete; 937250199Sgrehan 938250199Sgrehan /* Pass in the status */ 939250199Sgrehan rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = 940285236Swhu status; 941250199Sgrehan 942250199Sgrehanretry_send_cmplt: 943250199Sgrehan /* Send the completion */ 944250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, &rx_comp_msg, 945250199Sgrehan sizeof(nvsp_msg), tid, HV_VMBUS_PACKET_TYPE_COMPLETION, 0); 946250199Sgrehan if (ret == 0) { 947250199Sgrehan /* success */ 948250199Sgrehan /* no-op */ 949250199Sgrehan } else if (ret == EAGAIN) { 950250199Sgrehan /* no more room... wait a bit and attempt to retry 3 times */ 951250199Sgrehan retries++; 952250199Sgrehan 953250199Sgrehan if (retries < 4) { 954250199Sgrehan DELAY(100); 955250199Sgrehan goto retry_send_cmplt; 956250199Sgrehan } 957250199Sgrehan } 958250199Sgrehan} 959250199Sgrehan 960250199Sgrehan/* 961250199Sgrehan * Net VSC on channel callback 962250199Sgrehan */ 963250199Sgrehanstatic void 964250199Sgrehanhv_nv_on_channel_callback(void *context) 965250199Sgrehan{ 966250199Sgrehan struct hv_device *device = (struct hv_device *)context; 967250199Sgrehan netvsc_dev *net_dev; 968285236Swhu device_t dev = device->device; 969250199Sgrehan uint32_t bytes_rxed; 970250199Sgrehan uint64_t request_id; 971285236Swhu hv_vm_packet_descriptor *desc; 972250199Sgrehan uint8_t *buffer; 973285236Swhu int bufferlen = NETVSC_PACKET_SIZE; 974285236Swhu int ret = 0; 975250199Sgrehan 976285236Swhu net_dev = hv_nv_get_inbound_net_device(device); 977285236Swhu if (net_dev == NULL) 978250199Sgrehan return; 979250199Sgrehan 980285236Swhu buffer = net_dev->callback_buf; 981250199Sgrehan 982250199Sgrehan do { 983250199Sgrehan ret = hv_vmbus_channel_recv_packet_raw(device->channel, 984250199Sgrehan buffer, bufferlen, &bytes_rxed, &request_id); 985250199Sgrehan if (ret == 0) { 986250199Sgrehan if (bytes_rxed > 0) { 987250199Sgrehan desc = (hv_vm_packet_descriptor *)buffer; 988250199Sgrehan switch (desc->type) { 989250199Sgrehan case HV_VMBUS_PACKET_TYPE_COMPLETION: 990285236Swhu hv_nv_on_send_completion(net_dev, device, desc); 991250199Sgrehan break; 992250199Sgrehan case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: 993285236Swhu hv_nv_on_receive(net_dev, device, desc); 994250199Sgrehan break; 995250199Sgrehan default: 996285236Swhu device_printf(dev, 997285236Swhu "hv_cb recv unknow type %d " 998285236Swhu " packet\n", desc->type); 999250199Sgrehan break; 1000250199Sgrehan } 1001250199Sgrehan } else { 1002250199Sgrehan break; 1003250199Sgrehan } 1004250199Sgrehan } else if (ret == ENOBUFS) { 1005250199Sgrehan /* Handle large packet */ 1006285236Swhu if (bufferlen > NETVSC_PACKET_SIZE) { 1007285236Swhu free(buffer, M_NETVSC); 1008285236Swhu buffer = NULL; 1009285236Swhu } 1010285236Swhu 1011285236Swhu /* alloc new buffer */ 1012285236Swhu buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT); 1013250199Sgrehan if (buffer == NULL) { 1014285236Swhu device_printf(dev, 1015285236Swhu "hv_cb malloc buffer failed, len=%u\n", 1016285236Swhu bytes_rxed); 1017285236Swhu bufferlen = 0; 1018250199Sgrehan break; 1019250199Sgrehan } 1020250199Sgrehan bufferlen = bytes_rxed; 1021250199Sgrehan } 1022250199Sgrehan } while (1); 1023250199Sgrehan 1024285236Swhu if (bufferlen > NETVSC_PACKET_SIZE) 1025285236Swhu free(buffer, M_NETVSC); 1026250199Sgrehan} 1027