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$ 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 51250199Sgrehan 52250199Sgrehan/* 53250199Sgrehan * Forward declarations 54250199Sgrehan */ 55250199Sgrehanstatic void hv_nv_on_channel_callback(void *context); 56250199Sgrehanstatic int hv_nv_init_send_buffer_with_net_vsp(struct hv_device *device); 57250199Sgrehanstatic int hv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device); 58250199Sgrehanstatic int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); 59250199Sgrehanstatic int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev); 60250199Sgrehanstatic int hv_nv_connect_to_vsp(struct hv_device *device); 61250199Sgrehanstatic void hv_nv_on_send_completion(struct hv_device *device, 62250199Sgrehan hv_vm_packet_descriptor *pkt); 63250199Sgrehanstatic void hv_nv_on_receive(struct hv_device *device, 64250199Sgrehan hv_vm_packet_descriptor *pkt); 65250199Sgrehanstatic void hv_nv_send_receive_completion(struct hv_device *device, 66250199Sgrehan uint64_t tid); 67250199Sgrehan 68250199Sgrehan 69250199Sgrehan/* 70250199Sgrehan * 71250199Sgrehan */ 72250199Sgrehanstatic inline netvsc_dev * 73250199Sgrehanhv_nv_alloc_net_device(struct hv_device *device) 74250199Sgrehan{ 75250199Sgrehan netvsc_dev *net_dev; 76250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 77250199Sgrehan 78250199Sgrehan net_dev = malloc(sizeof(netvsc_dev), M_DEVBUF, M_NOWAIT | M_ZERO); 79250199Sgrehan if (net_dev == NULL) { 80250199Sgrehan return (NULL); 81250199Sgrehan } 82250199Sgrehan 83250199Sgrehan net_dev->dev = device; 84250199Sgrehan net_dev->destroy = FALSE; 85250199Sgrehan sc->net_dev = net_dev; 86250199Sgrehan 87250199Sgrehan return (net_dev); 88250199Sgrehan} 89250199Sgrehan 90250199Sgrehan/* 91250199Sgrehan * 92250199Sgrehan */ 93250199Sgrehanstatic inline netvsc_dev * 94250199Sgrehanhv_nv_get_outbound_net_device(struct hv_device *device) 95250199Sgrehan{ 96250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 97250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 98250199Sgrehan 99250199Sgrehan if ((net_dev != NULL) && net_dev->destroy) { 100250199Sgrehan return (NULL); 101250199Sgrehan } 102250199Sgrehan 103250199Sgrehan return (net_dev); 104250199Sgrehan} 105250199Sgrehan 106250199Sgrehan/* 107250199Sgrehan * 108250199Sgrehan */ 109250199Sgrehanstatic inline netvsc_dev * 110250199Sgrehanhv_nv_get_inbound_net_device(struct hv_device *device) 111250199Sgrehan{ 112250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 113250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 114250199Sgrehan 115250199Sgrehan if (net_dev == NULL) { 116250199Sgrehan return (net_dev); 117250199Sgrehan } 118250199Sgrehan /* 119250199Sgrehan * When the device is being destroyed; we only 120250199Sgrehan * permit incoming packets if and only if there 121250199Sgrehan * are outstanding sends. 122250199Sgrehan */ 123250199Sgrehan if (net_dev->destroy && net_dev->num_outstanding_sends == 0) { 124250199Sgrehan return (NULL); 125250199Sgrehan } 126250199Sgrehan 127250199Sgrehan return (net_dev); 128250199Sgrehan} 129250199Sgrehan 130250199Sgrehan/* 131250199Sgrehan * Net VSC initialize receive buffer with net VSP 132250199Sgrehan * 133250199Sgrehan * Net VSP: Network virtual services client, also known as the 134250199Sgrehan * Hyper-V extensible switch and the synthetic data path. 135250199Sgrehan */ 136250199Sgrehanstatic int 137250199Sgrehanhv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device) 138250199Sgrehan{ 139250199Sgrehan netvsc_dev *net_dev; 140250199Sgrehan nvsp_msg *init_pkt; 141250199Sgrehan int ret = 0; 142250199Sgrehan 143250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 144250199Sgrehan if (!net_dev) { 145250199Sgrehan return (ENODEV); 146250199Sgrehan } 147250199Sgrehan 148250199Sgrehan net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_DEVBUF, 149250199Sgrehan M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); 150250199Sgrehan if (net_dev->rx_buf == NULL) { 151250199Sgrehan ret = ENOMEM; 152250199Sgrehan goto cleanup; 153250199Sgrehan } 154250199Sgrehan 155250199Sgrehan /* 156250199Sgrehan * Establish the GPADL handle for this buffer on this channel. 157250199Sgrehan * Note: This call uses the vmbus connection rather than the 158250199Sgrehan * channel to establish the gpadl handle. 159250199Sgrehan * GPADL: Guest physical address descriptor list. 160250199Sgrehan */ 161250199Sgrehan ret = hv_vmbus_channel_establish_gpadl( 162250199Sgrehan device->channel, net_dev->rx_buf, 163250199Sgrehan net_dev->rx_buf_size, &net_dev->rx_buf_gpadl_handle); 164250199Sgrehan if (ret != 0) { 165250199Sgrehan goto cleanup; 166250199Sgrehan } 167250199Sgrehan 168250199Sgrehan /* sema_wait(&ext->channel_init_sema); KYS CHECK */ 169250199Sgrehan 170250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 171250199Sgrehan init_pkt = &net_dev->channel_init_packet; 172250199Sgrehan 173250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 174250199Sgrehan 175250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf; 176250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 177250199Sgrehan net_dev->rx_buf_gpadl_handle; 178250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 179250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 180250199Sgrehan 181250199Sgrehan /* Send the gpadl notification request */ 182250199Sgrehan 183250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 184266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 185250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 186250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 187250199Sgrehan if (ret != 0) { 188250199Sgrehan goto cleanup; 189250199Sgrehan } 190250199Sgrehan 191250199Sgrehan sema_wait(&net_dev->channel_init_sema); 192250199Sgrehan 193250199Sgrehan /* Check the response */ 194250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status 195250199Sgrehan != nvsp_status_success) { 196250199Sgrehan ret = EINVAL; 197250199Sgrehan goto cleanup; 198250199Sgrehan } 199250199Sgrehan 200250199Sgrehan net_dev->rx_section_count = 201250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; 202250199Sgrehan 203250199Sgrehan net_dev->rx_sections = malloc(net_dev->rx_section_count * 204250199Sgrehan sizeof(nvsp_1_rx_buf_section), M_DEVBUF, M_NOWAIT); 205250199Sgrehan if (net_dev->rx_sections == NULL) { 206250199Sgrehan ret = EINVAL; 207250199Sgrehan goto cleanup; 208250199Sgrehan } 209250199Sgrehan memcpy(net_dev->rx_sections, 210250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections, 211250199Sgrehan net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section)); 212250199Sgrehan 213250199Sgrehan 214250199Sgrehan /* 215250199Sgrehan * For first release, there should only be 1 section that represents 216250199Sgrehan * the entire receive buffer 217250199Sgrehan */ 218250199Sgrehan if (net_dev->rx_section_count != 1 219250199Sgrehan || net_dev->rx_sections->offset != 0) { 220250199Sgrehan ret = EINVAL; 221250199Sgrehan goto cleanup; 222250199Sgrehan } 223250199Sgrehan 224250199Sgrehan goto exit; 225250199Sgrehan 226250199Sgrehancleanup: 227250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 228250199Sgrehan 229250199Sgrehanexit: 230250199Sgrehan return (ret); 231250199Sgrehan} 232250199Sgrehan 233250199Sgrehan/* 234250199Sgrehan * Net VSC initialize send buffer with net VSP 235250199Sgrehan */ 236250199Sgrehanstatic int 237250199Sgrehanhv_nv_init_send_buffer_with_net_vsp(struct hv_device *device) 238250199Sgrehan{ 239250199Sgrehan netvsc_dev *net_dev; 240250199Sgrehan nvsp_msg *init_pkt; 241250199Sgrehan int ret = 0; 242250199Sgrehan 243250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 244250199Sgrehan if (!net_dev) { 245250199Sgrehan return (ENODEV); 246250199Sgrehan } 247250199Sgrehan 248250199Sgrehan net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_DEVBUF, 249250199Sgrehan M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); 250250199Sgrehan if (net_dev->send_buf == NULL) { 251250199Sgrehan ret = ENOMEM; 252250199Sgrehan goto cleanup; 253250199Sgrehan } 254250199Sgrehan 255250199Sgrehan /* 256250199Sgrehan * Establish the gpadl handle for this buffer on this channel. 257250199Sgrehan * Note: This call uses the vmbus connection rather than the 258250199Sgrehan * channel to establish the gpadl handle. 259250199Sgrehan */ 260250199Sgrehan ret = hv_vmbus_channel_establish_gpadl(device->channel, 261250199Sgrehan net_dev->send_buf, net_dev->send_buf_size, 262250199Sgrehan &net_dev->send_buf_gpadl_handle); 263250199Sgrehan if (ret != 0) { 264250199Sgrehan goto cleanup; 265250199Sgrehan } 266250199Sgrehan 267250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 268250199Sgrehan 269250199Sgrehan init_pkt = &net_dev->channel_init_packet; 270250199Sgrehan 271250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 272250199Sgrehan 273250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf; 274250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 275250199Sgrehan net_dev->send_buf_gpadl_handle; 276250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 277250199Sgrehan NETVSC_SEND_BUFFER_ID; 278250199Sgrehan 279250199Sgrehan /* Send the gpadl notification request */ 280250199Sgrehan 281250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 282266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 283250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 284250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 285250199Sgrehan if (ret != 0) { 286250199Sgrehan goto cleanup; 287250199Sgrehan } 288250199Sgrehan 289250199Sgrehan sema_wait(&net_dev->channel_init_sema); 290250199Sgrehan 291250199Sgrehan /* Check the response */ 292250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status 293250199Sgrehan != nvsp_status_success) { 294250199Sgrehan ret = EINVAL; 295250199Sgrehan goto cleanup; 296250199Sgrehan } 297250199Sgrehan 298250199Sgrehan net_dev->send_section_size = 299250199Sgrehan init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; 300250199Sgrehan 301250199Sgrehan goto exit; 302250199Sgrehan 303250199Sgrehancleanup: 304250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 305250199Sgrehan 306250199Sgrehanexit: 307250199Sgrehan return (ret); 308250199Sgrehan} 309250199Sgrehan 310250199Sgrehan/* 311250199Sgrehan * Net VSC destroy receive buffer 312250199Sgrehan */ 313250199Sgrehanstatic int 314250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev) 315250199Sgrehan{ 316250199Sgrehan nvsp_msg *revoke_pkt; 317250199Sgrehan int ret = 0; 318250199Sgrehan 319250199Sgrehan /* 320250199Sgrehan * If we got a section count, it means we received a 321250199Sgrehan * send_rx_buf_complete msg 322250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 323250199Sgrehan * we need to send a revoke msg here 324250199Sgrehan */ 325250199Sgrehan if (net_dev->rx_section_count) { 326250199Sgrehan /* Send the revoke receive buffer */ 327250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 328250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 329250199Sgrehan 330250199Sgrehan revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf; 331250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id = 332250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 333250199Sgrehan 334250199Sgrehan ret = hv_vmbus_channel_send_packet(net_dev->dev->channel, 335250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 336266794Smarius (uint64_t)(uintptr_t)revoke_pkt, 337250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 338250199Sgrehan 339250199Sgrehan /* 340250199Sgrehan * If we failed here, we might as well return and have a leak 341250199Sgrehan * rather than continue and a bugchk 342250199Sgrehan */ 343250199Sgrehan if (ret != 0) { 344250199Sgrehan return (ret); 345250199Sgrehan } 346250199Sgrehan } 347250199Sgrehan 348250199Sgrehan /* Tear down the gpadl on the vsp end */ 349250199Sgrehan if (net_dev->rx_buf_gpadl_handle) { 350250199Sgrehan ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel, 351250199Sgrehan net_dev->rx_buf_gpadl_handle); 352250199Sgrehan /* 353250199Sgrehan * If we failed here, we might as well return and have a leak 354250199Sgrehan * rather than continue and a bugchk 355250199Sgrehan */ 356250199Sgrehan if (ret != 0) { 357250199Sgrehan return (ret); 358250199Sgrehan } 359250199Sgrehan net_dev->rx_buf_gpadl_handle = 0; 360250199Sgrehan } 361250199Sgrehan 362250199Sgrehan if (net_dev->rx_buf) { 363250199Sgrehan /* Free up the receive buffer */ 364250199Sgrehan contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_DEVBUF); 365250199Sgrehan net_dev->rx_buf = NULL; 366250199Sgrehan } 367250199Sgrehan 368250199Sgrehan if (net_dev->rx_sections) { 369250199Sgrehan free(net_dev->rx_sections, M_DEVBUF); 370250199Sgrehan net_dev->rx_sections = NULL; 371250199Sgrehan net_dev->rx_section_count = 0; 372250199Sgrehan } 373250199Sgrehan 374250199Sgrehan return (ret); 375250199Sgrehan} 376250199Sgrehan 377250199Sgrehan/* 378250199Sgrehan * Net VSC destroy send buffer 379250199Sgrehan */ 380250199Sgrehanstatic int 381250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev) 382250199Sgrehan{ 383250199Sgrehan nvsp_msg *revoke_pkt; 384250199Sgrehan int ret = 0; 385250199Sgrehan 386250199Sgrehan /* 387250199Sgrehan * If we got a section count, it means we received a 388250199Sgrehan * send_rx_buf_complete msg 389250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 390250199Sgrehan * we need to send a revoke msg here 391250199Sgrehan */ 392250199Sgrehan if (net_dev->send_section_size) { 393250199Sgrehan /* Send the revoke send buffer */ 394250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 395250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 396250199Sgrehan 397250199Sgrehan revoke_pkt->hdr.msg_type = 398250199Sgrehan nvsp_msg_1_type_revoke_send_buf; 399250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id = 400250199Sgrehan NETVSC_SEND_BUFFER_ID; 401250199Sgrehan 402250199Sgrehan ret = hv_vmbus_channel_send_packet(net_dev->dev->channel, 403250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 404266794Smarius (uint64_t)(uintptr_t)revoke_pkt, 405250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 406250199Sgrehan /* 407250199Sgrehan * If we failed here, we might as well return and have a leak 408250199Sgrehan * rather than continue and a bugchk 409250199Sgrehan */ 410250199Sgrehan if (ret != 0) { 411250199Sgrehan return (ret); 412250199Sgrehan } 413250199Sgrehan } 414250199Sgrehan 415250199Sgrehan /* Tear down the gpadl on the vsp end */ 416250199Sgrehan if (net_dev->send_buf_gpadl_handle) { 417250199Sgrehan ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel, 418250199Sgrehan net_dev->send_buf_gpadl_handle); 419250199Sgrehan 420250199Sgrehan /* 421250199Sgrehan * If we failed here, we might as well return and have a leak 422250199Sgrehan * rather than continue and a bugchk 423250199Sgrehan */ 424250199Sgrehan if (ret != 0) { 425250199Sgrehan return (ret); 426250199Sgrehan } 427250199Sgrehan net_dev->send_buf_gpadl_handle = 0; 428250199Sgrehan } 429250199Sgrehan 430250199Sgrehan if (net_dev->send_buf) { 431250199Sgrehan /* Free up the receive buffer */ 432250199Sgrehan contigfree(net_dev->send_buf, net_dev->send_buf_size, M_DEVBUF); 433250199Sgrehan net_dev->send_buf = NULL; 434250199Sgrehan } 435250199Sgrehan 436250199Sgrehan return (ret); 437250199Sgrehan} 438250199Sgrehan 439250199Sgrehan 440250199Sgrehan/* 441250199Sgrehan * Attempt to negotiate the caller-specified NVSP version 442250199Sgrehan * 443250199Sgrehan * For NVSP v2, Server 2008 R2 does not set 444250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers 445250199Sgrehan * to the negotiated version, so we cannot rely on that. 446250199Sgrehan */ 447250199Sgrehanstatic int 448250199Sgrehanhv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev, 449250199Sgrehan uint32_t nvsp_ver) 450250199Sgrehan{ 451250199Sgrehan nvsp_msg *init_pkt; 452250199Sgrehan int ret; 453250199Sgrehan 454250199Sgrehan init_pkt = &net_dev->channel_init_packet; 455250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 456250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_type_init; 457250199Sgrehan 458250199Sgrehan /* 459250199Sgrehan * Specify parameter as the only acceptable protocol version 460250199Sgrehan */ 461250199Sgrehan init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver; 462250199Sgrehan init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver; 463250199Sgrehan 464250199Sgrehan /* Send the init request */ 465250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 466266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 467250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 468250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 469250199Sgrehan if (ret != 0) 470250199Sgrehan return (-1); 471250199Sgrehan 472250199Sgrehan sema_wait(&net_dev->channel_init_sema); 473250199Sgrehan 474250199Sgrehan if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success) 475250199Sgrehan return (EINVAL); 476250199Sgrehan 477250199Sgrehan return (0); 478250199Sgrehan} 479250199Sgrehan 480250199Sgrehan/* 481250199Sgrehan * Send NDIS version 2 config packet containing MTU. 482250199Sgrehan * 483250199Sgrehan * Not valid for NDIS version 1. 484250199Sgrehan */ 485250199Sgrehanstatic int 486250199Sgrehanhv_nv_send_ndis_config(struct hv_device *device, uint32_t mtu) 487250199Sgrehan{ 488250199Sgrehan netvsc_dev *net_dev; 489250199Sgrehan nvsp_msg *init_pkt; 490250199Sgrehan int ret; 491250199Sgrehan 492250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 493250199Sgrehan if (!net_dev) 494250199Sgrehan return (-ENODEV); 495250199Sgrehan 496250199Sgrehan /* 497250199Sgrehan * Set up configuration packet, write MTU 498250199Sgrehan * Indicate we are capable of handling VLAN tags 499250199Sgrehan */ 500250199Sgrehan init_pkt = &net_dev->channel_init_packet; 501250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 502250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config; 503250199Sgrehan init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu; 504250199Sgrehan init_pkt-> 505250199Sgrehan msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q 506250199Sgrehan = 1; 507250199Sgrehan 508250199Sgrehan /* Send the configuration packet */ 509250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 510266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 511250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 512250199Sgrehan if (ret != 0) 513250199Sgrehan return (-EINVAL); 514250199Sgrehan 515250199Sgrehan return (0); 516250199Sgrehan} 517250199Sgrehan 518250199Sgrehan/* 519250199Sgrehan * Net VSC connect to VSP 520250199Sgrehan */ 521250199Sgrehanstatic int 522250199Sgrehanhv_nv_connect_to_vsp(struct hv_device *device) 523250199Sgrehan{ 524250199Sgrehan netvsc_dev *net_dev; 525250199Sgrehan nvsp_msg *init_pkt; 526250199Sgrehan uint32_t nvsp_vers; 527250199Sgrehan uint32_t ndis_version; 528250199Sgrehan int ret = 0; 529250199Sgrehan device_t dev = device->device; 530250199Sgrehan hn_softc_t *sc = device_get_softc(dev); 531250199Sgrehan struct ifnet *ifp = sc->arpcom.ac_ifp; 532250199Sgrehan 533250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 534250199Sgrehan if (!net_dev) { 535250199Sgrehan return (ENODEV); 536250199Sgrehan } 537250199Sgrehan 538250199Sgrehan /* 539250199Sgrehan * Negotiate the NVSP version. Try NVSP v2 first. 540250199Sgrehan */ 541250199Sgrehan nvsp_vers = NVSP_PROTOCOL_VERSION_2; 542250199Sgrehan ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers); 543250199Sgrehan if (ret != 0) { 544250199Sgrehan /* NVSP v2 failed, try NVSP v1 */ 545250199Sgrehan nvsp_vers = NVSP_PROTOCOL_VERSION_1; 546250199Sgrehan ret = hv_nv_negotiate_nvsp_protocol(device, net_dev, nvsp_vers); 547250199Sgrehan if (ret != 0) { 548250199Sgrehan /* NVSP v1 failed, return bad status */ 549250199Sgrehan return (ret); 550250199Sgrehan } 551250199Sgrehan } 552250199Sgrehan net_dev->nvsp_version = nvsp_vers; 553250199Sgrehan 554250199Sgrehan /* 555250199Sgrehan * Set the MTU if supported by this NVSP protocol version 556250199Sgrehan * This needs to be right after the NVSP init message per Haiyang 557250199Sgrehan */ 558250199Sgrehan if (nvsp_vers >= NVSP_PROTOCOL_VERSION_2) 559250199Sgrehan ret = hv_nv_send_ndis_config(device, ifp->if_mtu); 560250199Sgrehan 561250199Sgrehan /* 562250199Sgrehan * Send the NDIS version 563250199Sgrehan */ 564250199Sgrehan init_pkt = &net_dev->channel_init_packet; 565250199Sgrehan 566250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 567250199Sgrehan 568250199Sgrehan /* 569250199Sgrehan * Updated to version 5.1, minimum, for VLAN per Haiyang 570250199Sgrehan */ 571250199Sgrehan ndis_version = NDIS_VERSION; 572250199Sgrehan 573250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; 574250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = 575250199Sgrehan (ndis_version & 0xFFFF0000) >> 16; 576250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers = 577250199Sgrehan ndis_version & 0xFFFF; 578250199Sgrehan 579250199Sgrehan /* Send the init request */ 580250199Sgrehan 581250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 582266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 583250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 584250199Sgrehan if (ret != 0) { 585250199Sgrehan goto cleanup; 586250199Sgrehan } 587250199Sgrehan /* 588250199Sgrehan * TODO: BUGBUG - We have to wait for the above msg since the netvsp 589250199Sgrehan * uses KMCL which acknowledges packet (completion packet) 590250199Sgrehan * since our Vmbus always set the 591250199Sgrehan * HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag 592250199Sgrehan */ 593250199Sgrehan /* sema_wait(&NetVscChannel->channel_init_sema); */ 594250199Sgrehan 595250199Sgrehan /* Post the big receive buffer to NetVSP */ 596250199Sgrehan ret = hv_nv_init_rx_buffer_with_net_vsp(device); 597250199Sgrehan if (ret == 0) 598250199Sgrehan ret = hv_nv_init_send_buffer_with_net_vsp(device); 599250199Sgrehan 600250199Sgrehancleanup: 601250199Sgrehan return (ret); 602250199Sgrehan} 603250199Sgrehan 604250199Sgrehan/* 605250199Sgrehan * Net VSC disconnect from VSP 606250199Sgrehan */ 607250199Sgrehanstatic void 608250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev) 609250199Sgrehan{ 610250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 611250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 612250199Sgrehan} 613250199Sgrehan 614250199Sgrehan/* 615250199Sgrehan * Net VSC on device add 616250199Sgrehan * 617250199Sgrehan * Callback when the device belonging to this driver is added 618250199Sgrehan */ 619250199Sgrehannetvsc_dev * 620250199Sgrehanhv_nv_on_device_add(struct hv_device *device, void *additional_info) 621250199Sgrehan{ 622250199Sgrehan netvsc_dev *net_dev; 623250199Sgrehan netvsc_packet *packet; 624250199Sgrehan netvsc_packet *next_packet; 625250199Sgrehan int i, ret = 0; 626250199Sgrehan 627250199Sgrehan net_dev = hv_nv_alloc_net_device(device); 628250199Sgrehan if (!net_dev) 629250199Sgrehan goto cleanup; 630250199Sgrehan 631250199Sgrehan /* Initialize the NetVSC channel extension */ 632250199Sgrehan net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; 633250199Sgrehan mtx_init(&net_dev->rx_pkt_list_lock, "HV-RPL", NULL, 634250199Sgrehan MTX_SPIN | MTX_RECURSE); 635250199Sgrehan 636250199Sgrehan net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; 637250199Sgrehan 638250199Sgrehan /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */ 639250199Sgrehan STAILQ_INIT(&net_dev->myrx_packet_list); 640250199Sgrehan 641250199Sgrehan /* 642250199Sgrehan * malloc a sufficient number of netvsc_packet buffers to hold 643250199Sgrehan * a packet list. Add them to the netvsc device packet queue. 644250199Sgrehan */ 645250199Sgrehan for (i=0; i < NETVSC_RECEIVE_PACKETLIST_COUNT; i++) { 646250199Sgrehan packet = malloc(sizeof(netvsc_packet) + 647250199Sgrehan (NETVSC_RECEIVE_SG_COUNT * sizeof(hv_vmbus_page_buffer)), 648250199Sgrehan M_DEVBUF, M_NOWAIT | M_ZERO); 649250199Sgrehan if (!packet) { 650250199Sgrehan break; 651250199Sgrehan } 652250199Sgrehan STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, 653250199Sgrehan mylist_entry); 654250199Sgrehan } 655250199Sgrehan 656250199Sgrehan sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); 657250199Sgrehan 658250199Sgrehan /* 659250199Sgrehan * Open the channel 660250199Sgrehan */ 661250199Sgrehan ret = hv_vmbus_channel_open(device->channel, 662250199Sgrehan NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE, 663250199Sgrehan NULL, 0, hv_nv_on_channel_callback, device); 664250199Sgrehan if (ret != 0) 665250199Sgrehan goto cleanup; 666250199Sgrehan 667250199Sgrehan /* 668250199Sgrehan * Connect with the NetVsp 669250199Sgrehan */ 670250199Sgrehan ret = hv_nv_connect_to_vsp(device); 671250199Sgrehan if (ret != 0) 672250199Sgrehan goto close; 673250199Sgrehan 674250199Sgrehan return (net_dev); 675250199Sgrehan 676250199Sgrehanclose: 677250199Sgrehan /* Now, we can close the channel safely */ 678250199Sgrehan 679250199Sgrehan hv_vmbus_channel_close(device->channel); 680250199Sgrehan 681250199Sgrehancleanup: 682250199Sgrehan /* 683250199Sgrehan * Free the packet buffers on the netvsc device packet queue. 684250199Sgrehan * Release other resources. 685250199Sgrehan */ 686250199Sgrehan if (net_dev) { 687250199Sgrehan sema_destroy(&net_dev->channel_init_sema); 688250199Sgrehan 689250199Sgrehan packet = STAILQ_FIRST(&net_dev->myrx_packet_list); 690250199Sgrehan while (packet != NULL) { 691250199Sgrehan next_packet = STAILQ_NEXT(packet, mylist_entry); 692250199Sgrehan free(packet, M_DEVBUF); 693250199Sgrehan packet = next_packet; 694250199Sgrehan } 695250199Sgrehan /* Reset the list to initial state */ 696250199Sgrehan STAILQ_INIT(&net_dev->myrx_packet_list); 697250199Sgrehan 698250199Sgrehan mtx_destroy(&net_dev->rx_pkt_list_lock); 699250199Sgrehan 700250199Sgrehan free(net_dev, M_DEVBUF); 701250199Sgrehan } 702250199Sgrehan 703250199Sgrehan return (NULL); 704250199Sgrehan} 705250199Sgrehan 706250199Sgrehan/* 707250199Sgrehan * Net VSC on device remove 708250199Sgrehan */ 709250199Sgrehanint 710250199Sgrehanhv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel) 711250199Sgrehan{ 712250199Sgrehan netvsc_packet *net_vsc_pkt; 713250199Sgrehan netvsc_packet *next_net_vsc_pkt; 714250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 715250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 716250199Sgrehan 717250199Sgrehan /* Stop outbound traffic ie sends and receives completions */ 718250199Sgrehan mtx_lock(&device->channel->inbound_lock); 719250199Sgrehan net_dev->destroy = TRUE; 720250199Sgrehan mtx_unlock(&device->channel->inbound_lock); 721250199Sgrehan 722250199Sgrehan /* Wait for all send completions */ 723250199Sgrehan while (net_dev->num_outstanding_sends) { 724250199Sgrehan DELAY(100); 725250199Sgrehan } 726250199Sgrehan 727250199Sgrehan hv_nv_disconnect_from_vsp(net_dev); 728250199Sgrehan 729250199Sgrehan /* At this point, no one should be accessing net_dev except in here */ 730250199Sgrehan 731250199Sgrehan /* Now, we can close the channel safely */ 732250199Sgrehan 733250199Sgrehan if (!destroy_channel) { 734250199Sgrehan device->channel->state = 735250199Sgrehan HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE; 736250199Sgrehan } 737250199Sgrehan 738250199Sgrehan hv_vmbus_channel_close(device->channel); 739250199Sgrehan 740250199Sgrehan /* Release all resources */ 741250199Sgrehan net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list); 742250199Sgrehan while (net_vsc_pkt != NULL) { 743250199Sgrehan next_net_vsc_pkt = STAILQ_NEXT(net_vsc_pkt, mylist_entry); 744250199Sgrehan free(net_vsc_pkt, M_DEVBUF); 745250199Sgrehan net_vsc_pkt = next_net_vsc_pkt; 746250199Sgrehan } 747250199Sgrehan 748250199Sgrehan /* Reset the list to initial state */ 749250199Sgrehan STAILQ_INIT(&net_dev->myrx_packet_list); 750250199Sgrehan 751250199Sgrehan mtx_destroy(&net_dev->rx_pkt_list_lock); 752250199Sgrehan sema_destroy(&net_dev->channel_init_sema); 753250199Sgrehan free(net_dev, M_DEVBUF); 754250199Sgrehan 755250199Sgrehan return (0); 756250199Sgrehan} 757250199Sgrehan 758250199Sgrehan/* 759250199Sgrehan * Net VSC on send completion 760250199Sgrehan */ 761250199Sgrehanstatic void 762250199Sgrehanhv_nv_on_send_completion(struct hv_device *device, hv_vm_packet_descriptor *pkt) 763250199Sgrehan{ 764250199Sgrehan netvsc_dev *net_dev; 765250199Sgrehan nvsp_msg *nvsp_msg_pkt; 766250199Sgrehan netvsc_packet *net_vsc_pkt; 767250199Sgrehan 768250199Sgrehan net_dev = hv_nv_get_inbound_net_device(device); 769250199Sgrehan if (!net_dev) { 770250199Sgrehan return; 771250199Sgrehan } 772250199Sgrehan 773250199Sgrehan nvsp_msg_pkt = 774250199Sgrehan (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); 775250199Sgrehan 776250199Sgrehan if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete 777250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 778250199Sgrehan == nvsp_msg_1_type_send_rx_buf_complete 779250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 780250199Sgrehan == nvsp_msg_1_type_send_send_buf_complete) { 781250199Sgrehan /* Copy the response back */ 782250199Sgrehan memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, 783250199Sgrehan sizeof(nvsp_msg)); 784250199Sgrehan sema_post(&net_dev->channel_init_sema); 785250199Sgrehan } else if (nvsp_msg_pkt->hdr.msg_type == 786250199Sgrehan nvsp_msg_1_type_send_rndis_pkt_complete) { 787250199Sgrehan /* Get the send context */ 788250199Sgrehan net_vsc_pkt = 789250199Sgrehan (netvsc_packet *)(unsigned long)pkt->transaction_id; 790250199Sgrehan 791250199Sgrehan /* Notify the layer above us */ 792250199Sgrehan net_vsc_pkt->compl.send.on_send_completion( 793250199Sgrehan net_vsc_pkt->compl.send.send_completion_context); 794250199Sgrehan 795250199Sgrehan atomic_subtract_int(&net_dev->num_outstanding_sends, 1); 796250199Sgrehan } 797250199Sgrehan} 798250199Sgrehan 799250199Sgrehan/* 800250199Sgrehan * Net VSC on send 801250199Sgrehan * Sends a packet on the specified Hyper-V device. 802250199Sgrehan * Returns 0 on success, non-zero on failure. 803250199Sgrehan */ 804250199Sgrehanint 805250199Sgrehanhv_nv_on_send(struct hv_device *device, netvsc_packet *pkt) 806250199Sgrehan{ 807250199Sgrehan netvsc_dev *net_dev; 808250199Sgrehan nvsp_msg send_msg; 809250199Sgrehan int ret; 810250199Sgrehan 811250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 812250199Sgrehan if (!net_dev) 813250199Sgrehan return (ENODEV); 814250199Sgrehan 815250199Sgrehan send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt; 816250199Sgrehan if (pkt->is_data_pkt) { 817250199Sgrehan /* 0 is RMC_DATA */ 818250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0; 819250199Sgrehan } else { 820250199Sgrehan /* 1 is RMC_CONTROL */ 821250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; 822250199Sgrehan } 823250199Sgrehan 824250199Sgrehan /* Not using send buffer section */ 825250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = 826250199Sgrehan 0xFFFFFFFF; 827250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 0; 828250199Sgrehan 829250199Sgrehan if (pkt->page_buf_count) { 830250199Sgrehan ret = hv_vmbus_channel_send_packet_pagebuffer(device->channel, 831250199Sgrehan pkt->page_buffers, pkt->page_buf_count, 832266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt); 833250199Sgrehan } else { 834250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, 835266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt, 836250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 837250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 838250199Sgrehan } 839250199Sgrehan 840250199Sgrehan /* Record outstanding send only if send_packet() succeeded */ 841250199Sgrehan if (ret == 0) 842250199Sgrehan atomic_add_int(&net_dev->num_outstanding_sends, 1); 843250199Sgrehan 844250199Sgrehan return (ret); 845250199Sgrehan} 846250199Sgrehan 847250199Sgrehan/* 848250199Sgrehan * Net VSC on receive 849250199Sgrehan * 850250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively 851250199Sgrehan * with virtual addresses. 852250199Sgrehan */ 853250199Sgrehanstatic void 854250199Sgrehanhv_nv_on_receive(struct hv_device *device, hv_vm_packet_descriptor *pkt) 855250199Sgrehan{ 856250199Sgrehan netvsc_dev *net_dev; 857250199Sgrehan hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; 858250199Sgrehan nvsp_msg *nvsp_msg_pkt; 859250199Sgrehan netvsc_packet *net_vsc_pkt = NULL; 860250199Sgrehan unsigned long start; 861250199Sgrehan xfer_page_packet *xfer_page_pkt = NULL; 862250199Sgrehan STAILQ_HEAD(PKT_LIST, netvsc_packet_) mylist_head = 863250199Sgrehan STAILQ_HEAD_INITIALIZER(mylist_head); 864250199Sgrehan int count = 0; 865250199Sgrehan int i = 0; 866250199Sgrehan 867250199Sgrehan net_dev = hv_nv_get_inbound_net_device(device); 868250199Sgrehan if (!net_dev) 869250199Sgrehan return; 870250199Sgrehan 871250199Sgrehan /* 872250199Sgrehan * All inbound packets other than send completion should be 873250199Sgrehan * xfer page packet. 874250199Sgrehan */ 875250199Sgrehan if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) 876250199Sgrehan return; 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 */ 882250199Sgrehan if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) 883250199Sgrehan return; 884250199Sgrehan 885250199Sgrehan vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt; 886250199Sgrehan 887250199Sgrehan if (vm_xfer_page_pkt->transfer_page_set_id 888250199Sgrehan != NETVSC_RECEIVE_BUFFER_ID) { 889250199Sgrehan return; 890250199Sgrehan } 891250199Sgrehan 892250199Sgrehan STAILQ_INIT(&mylist_head); 893250199Sgrehan 894250199Sgrehan /* 895250199Sgrehan * Grab free packets (range count + 1) to represent this xfer page 896250199Sgrehan * packet. +1 to represent the xfer page packet itself. We grab it 897250199Sgrehan * here so that we know exactly how many we can fulfill. 898250199Sgrehan */ 899250199Sgrehan mtx_lock_spin(&net_dev->rx_pkt_list_lock); 900250199Sgrehan while (!STAILQ_EMPTY(&net_dev->myrx_packet_list)) { 901250199Sgrehan net_vsc_pkt = STAILQ_FIRST(&net_dev->myrx_packet_list); 902250199Sgrehan STAILQ_REMOVE_HEAD(&net_dev->myrx_packet_list, mylist_entry); 903250199Sgrehan 904250199Sgrehan STAILQ_INSERT_TAIL(&mylist_head, net_vsc_pkt, mylist_entry); 905250199Sgrehan 906250199Sgrehan if (++count == vm_xfer_page_pkt->range_count + 1) 907250199Sgrehan break; 908250199Sgrehan } 909250199Sgrehan 910250199Sgrehan mtx_unlock_spin(&net_dev->rx_pkt_list_lock); 911250199Sgrehan 912250199Sgrehan /* 913250199Sgrehan * We need at least 2 netvsc pkts (1 to represent the xfer page 914250199Sgrehan * and at least 1 for the range) i.e. we can handle some of the 915250199Sgrehan * xfer page packet ranges... 916250199Sgrehan */ 917250199Sgrehan if (count < 2) { 918250199Sgrehan /* Return netvsc packet to the freelist */ 919250199Sgrehan mtx_lock_spin(&net_dev->rx_pkt_list_lock); 920250199Sgrehan for (i=count; i != 0; i--) { 921250199Sgrehan net_vsc_pkt = STAILQ_FIRST(&mylist_head); 922250199Sgrehan STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); 923250199Sgrehan 924250199Sgrehan STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, 925250199Sgrehan net_vsc_pkt, mylist_entry); 926250199Sgrehan } 927250199Sgrehan mtx_unlock_spin(&net_dev->rx_pkt_list_lock); 928250199Sgrehan 929250199Sgrehan hv_nv_send_receive_completion(device, 930250199Sgrehan vm_xfer_page_pkt->d.transaction_id); 931250199Sgrehan 932250199Sgrehan return; 933250199Sgrehan } 934250199Sgrehan 935250199Sgrehan /* Take the first packet in the list */ 936250199Sgrehan xfer_page_pkt = (xfer_page_packet *)STAILQ_FIRST(&mylist_head); 937250199Sgrehan STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); 938250199Sgrehan 939250199Sgrehan /* This is how many data packets we can supply */ 940250199Sgrehan xfer_page_pkt->count = count - 1; 941250199Sgrehan 942250199Sgrehan /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 943250199Sgrehan for (i=0; i < (count - 1); i++) { 944250199Sgrehan net_vsc_pkt = STAILQ_FIRST(&mylist_head); 945250199Sgrehan STAILQ_REMOVE_HEAD(&mylist_head, mylist_entry); 946250199Sgrehan 947250199Sgrehan /* 948250199Sgrehan * Initialize the netvsc packet 949250199Sgrehan */ 950250199Sgrehan net_vsc_pkt->xfer_page_pkt = xfer_page_pkt; 951250199Sgrehan net_vsc_pkt->compl.rx.rx_completion_context = net_vsc_pkt; 952250199Sgrehan net_vsc_pkt->device = device; 953250199Sgrehan /* Save this so that we can send it back */ 954250199Sgrehan net_vsc_pkt->compl.rx.rx_completion_tid = 955250199Sgrehan vm_xfer_page_pkt->d.transaction_id; 956250199Sgrehan 957250199Sgrehan net_vsc_pkt->tot_data_buf_len = 958250199Sgrehan vm_xfer_page_pkt->ranges[i].byte_count; 959250199Sgrehan net_vsc_pkt->page_buf_count = 1; 960250199Sgrehan 961250199Sgrehan net_vsc_pkt->page_buffers[0].length = 962250199Sgrehan vm_xfer_page_pkt->ranges[i].byte_count; 963250199Sgrehan 964250199Sgrehan /* The virtual address of the packet in the receive buffer */ 965250199Sgrehan start = ((unsigned long)net_dev->rx_buf + 966250199Sgrehan vm_xfer_page_pkt->ranges[i].byte_offset); 967250199Sgrehan start = ((unsigned long)start) & ~(PAGE_SIZE - 1); 968250199Sgrehan 969250199Sgrehan /* Page number of the virtual page containing packet start */ 970250199Sgrehan net_vsc_pkt->page_buffers[0].pfn = start >> PAGE_SHIFT; 971250199Sgrehan 972250199Sgrehan /* Calculate the page relative offset */ 973250199Sgrehan net_vsc_pkt->page_buffers[0].offset = 974250199Sgrehan vm_xfer_page_pkt->ranges[i].byte_offset & (PAGE_SIZE - 1); 975250199Sgrehan 976250199Sgrehan /* 977250199Sgrehan * In this implementation, we are dealing with virtual 978250199Sgrehan * addresses exclusively. Since we aren't using physical 979250199Sgrehan * addresses at all, we don't care if a packet crosses a 980250199Sgrehan * page boundary. For this reason, the original code to 981250199Sgrehan * check for and handle page crossings has been removed. 982250199Sgrehan */ 983250199Sgrehan 984250199Sgrehan /* 985250199Sgrehan * Pass it to the upper layer. The receive completion call 986250199Sgrehan * has been moved into this function. 987250199Sgrehan */ 988250199Sgrehan hv_rf_on_receive(device, net_vsc_pkt); 989250199Sgrehan 990250199Sgrehan /* 991250199Sgrehan * Moved completion call back here so that all received 992250199Sgrehan * messages (not just data messages) will trigger a response 993250199Sgrehan * message back to the host. 994250199Sgrehan */ 995250199Sgrehan hv_nv_on_receive_completion(net_vsc_pkt); 996250199Sgrehan } 997250199Sgrehan} 998250199Sgrehan 999250199Sgrehan/* 1000250199Sgrehan * Net VSC send receive completion 1001250199Sgrehan */ 1002250199Sgrehanstatic void 1003250199Sgrehanhv_nv_send_receive_completion(struct hv_device *device, uint64_t tid) 1004250199Sgrehan{ 1005250199Sgrehan nvsp_msg rx_comp_msg; 1006250199Sgrehan int retries = 0; 1007250199Sgrehan int ret = 0; 1008250199Sgrehan 1009250199Sgrehan rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete; 1010250199Sgrehan 1011250199Sgrehan /* Pass in the status */ 1012250199Sgrehan rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = 1013250199Sgrehan nvsp_status_success; 1014250199Sgrehan 1015250199Sgrehanretry_send_cmplt: 1016250199Sgrehan /* Send the completion */ 1017250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, &rx_comp_msg, 1018250199Sgrehan sizeof(nvsp_msg), tid, HV_VMBUS_PACKET_TYPE_COMPLETION, 0); 1019250199Sgrehan if (ret == 0) { 1020250199Sgrehan /* success */ 1021250199Sgrehan /* no-op */ 1022250199Sgrehan } else if (ret == EAGAIN) { 1023250199Sgrehan /* no more room... wait a bit and attempt to retry 3 times */ 1024250199Sgrehan retries++; 1025250199Sgrehan 1026250199Sgrehan if (retries < 4) { 1027250199Sgrehan DELAY(100); 1028250199Sgrehan goto retry_send_cmplt; 1029250199Sgrehan } 1030250199Sgrehan } 1031250199Sgrehan} 1032250199Sgrehan 1033250199Sgrehan/* 1034250199Sgrehan * Net VSC on receive completion 1035250199Sgrehan * 1036250199Sgrehan * Send a receive completion packet to RNDIS device (ie NetVsp) 1037250199Sgrehan */ 1038250199Sgrehanvoid 1039250199Sgrehanhv_nv_on_receive_completion(void *context) 1040250199Sgrehan{ 1041250199Sgrehan netvsc_packet *packet = (netvsc_packet *)context; 1042250199Sgrehan struct hv_device *device = (struct hv_device *)packet->device; 1043250199Sgrehan netvsc_dev *net_dev; 1044250199Sgrehan uint64_t tid = 0; 1045250199Sgrehan boolean_t send_rx_completion = FALSE; 1046250199Sgrehan 1047250199Sgrehan /* 1048250199Sgrehan * Even though it seems logical to do a hv_nv_get_outbound_net_device() 1049250199Sgrehan * here to send out receive completion, we are using 1050250199Sgrehan * hv_nv_get_inbound_net_device() since we may have disabled 1051250199Sgrehan * outbound traffic already. 1052250199Sgrehan */ 1053250199Sgrehan net_dev = hv_nv_get_inbound_net_device(device); 1054250199Sgrehan if (net_dev == NULL) 1055250199Sgrehan return; 1056250199Sgrehan 1057250199Sgrehan /* Overloading use of the lock. */ 1058250199Sgrehan mtx_lock_spin(&net_dev->rx_pkt_list_lock); 1059250199Sgrehan 1060250199Sgrehan packet->xfer_page_pkt->count--; 1061250199Sgrehan 1062250199Sgrehan /* 1063250199Sgrehan * Last one in the line that represent 1 xfer page packet. 1064250199Sgrehan * Return the xfer page packet itself to the free list. 1065250199Sgrehan */ 1066250199Sgrehan if (packet->xfer_page_pkt->count == 0) { 1067250199Sgrehan send_rx_completion = TRUE; 1068250199Sgrehan tid = packet->compl.rx.rx_completion_tid; 1069250199Sgrehan STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, 1070250199Sgrehan (netvsc_packet *)(packet->xfer_page_pkt), mylist_entry); 1071250199Sgrehan } 1072250199Sgrehan 1073250199Sgrehan /* Put the packet back on the free list */ 1074250199Sgrehan STAILQ_INSERT_TAIL(&net_dev->myrx_packet_list, packet, mylist_entry); 1075250199Sgrehan mtx_unlock_spin(&net_dev->rx_pkt_list_lock); 1076250199Sgrehan 1077250199Sgrehan /* Send a receive completion for the xfer page packet */ 1078250199Sgrehan if (send_rx_completion) 1079250199Sgrehan hv_nv_send_receive_completion(device, tid); 1080250199Sgrehan} 1081250199Sgrehan 1082250199Sgrehan/* 1083250199Sgrehan * Net VSC on channel callback 1084250199Sgrehan */ 1085250199Sgrehanstatic void 1086250199Sgrehanhv_nv_on_channel_callback(void *context) 1087250199Sgrehan{ 1088250199Sgrehan /* Fixme: Magic number */ 1089250199Sgrehan const int net_pkt_size = 2048; 1090250199Sgrehan struct hv_device *device = (struct hv_device *)context; 1091250199Sgrehan netvsc_dev *net_dev; 1092250199Sgrehan uint32_t bytes_rxed; 1093250199Sgrehan uint64_t request_id; 1094250199Sgrehan uint8_t *packet; 1095250199Sgrehan hv_vm_packet_descriptor *desc; 1096250199Sgrehan uint8_t *buffer; 1097250199Sgrehan int bufferlen = net_pkt_size; 1098250199Sgrehan int ret = 0; 1099250199Sgrehan 1100250199Sgrehan packet = malloc(net_pkt_size * sizeof(uint8_t), M_DEVBUF, M_NOWAIT); 1101250199Sgrehan if (!packet) 1102250199Sgrehan return; 1103250199Sgrehan 1104250199Sgrehan buffer = packet; 1105250199Sgrehan 1106250199Sgrehan net_dev = hv_nv_get_inbound_net_device(device); 1107250199Sgrehan if (net_dev == NULL) 1108250199Sgrehan goto out; 1109250199Sgrehan 1110250199Sgrehan do { 1111250199Sgrehan ret = hv_vmbus_channel_recv_packet_raw(device->channel, 1112250199Sgrehan buffer, bufferlen, &bytes_rxed, &request_id); 1113250199Sgrehan if (ret == 0) { 1114250199Sgrehan if (bytes_rxed > 0) { 1115250199Sgrehan desc = (hv_vm_packet_descriptor *)buffer; 1116250199Sgrehan switch (desc->type) { 1117250199Sgrehan case HV_VMBUS_PACKET_TYPE_COMPLETION: 1118250199Sgrehan hv_nv_on_send_completion(device, desc); 1119250199Sgrehan break; 1120250199Sgrehan case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: 1121250199Sgrehan hv_nv_on_receive(device, desc); 1122250199Sgrehan break; 1123250199Sgrehan default: 1124250199Sgrehan break; 1125250199Sgrehan } 1126250199Sgrehan } else { 1127250199Sgrehan break; 1128250199Sgrehan } 1129250199Sgrehan } else if (ret == ENOBUFS) { 1130250199Sgrehan /* Handle large packet */ 1131250199Sgrehan free(buffer, M_DEVBUF); 1132250199Sgrehan buffer = malloc(bytes_rxed, M_DEVBUF, M_NOWAIT); 1133250199Sgrehan if (buffer == NULL) { 1134250199Sgrehan break; 1135250199Sgrehan } 1136250199Sgrehan bufferlen = bytes_rxed; 1137250199Sgrehan } 1138250199Sgrehan } while (1); 1139250199Sgrehan 1140250199Sgrehanout: 1141250199Sgrehan free(buffer, M_DEVBUF); 1142250199Sgrehan} 1143250199Sgrehan 1144