hn_nvs.c revision 301952
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 301952 2016-06-16 05:24:00Z 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); 60250199Sgrehanstatic int hv_nv_init_send_buffer_with_net_vsp(struct hv_device *device); 61250199Sgrehanstatic int hv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device); 62250199Sgrehanstatic int hv_nv_destroy_send_buffer(netvsc_dev *net_dev); 63250199Sgrehanstatic int hv_nv_destroy_rx_buffer(netvsc_dev *net_dev); 64250199Sgrehanstatic int hv_nv_connect_to_vsp(struct hv_device *device); 65285236Swhustatic void hv_nv_on_send_completion(netvsc_dev *net_dev, 66301943Ssephe struct hv_device *device, struct hv_vmbus_channel *, hv_vm_packet_descriptor *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, 70301912Ssephe struct hv_device *device, struct hv_vmbus_channel *chan, 71301912Ssephe hv_vm_packet_descriptor *pkt); 72250199Sgrehan 73250199Sgrehan/* 74250199Sgrehan * 75250199Sgrehan */ 76250199Sgrehanstatic inline netvsc_dev * 77250199Sgrehanhv_nv_alloc_net_device(struct hv_device *device) 78250199Sgrehan{ 79250199Sgrehan netvsc_dev *net_dev; 80250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 81250199Sgrehan 82301859Ssephe net_dev = malloc(sizeof(netvsc_dev), M_NETVSC, M_WAITOK | M_ZERO); 83250199Sgrehan 84250199Sgrehan net_dev->dev = device; 85250199Sgrehan net_dev->destroy = FALSE; 86250199Sgrehan sc->net_dev = net_dev; 87250199Sgrehan 88250199Sgrehan return (net_dev); 89250199Sgrehan} 90250199Sgrehan 91250199Sgrehan/* 92250199Sgrehan * 93250199Sgrehan */ 94250199Sgrehanstatic inline netvsc_dev * 95250199Sgrehanhv_nv_get_outbound_net_device(struct hv_device *device) 96250199Sgrehan{ 97250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 98250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 99250199Sgrehan 100250199Sgrehan if ((net_dev != NULL) && net_dev->destroy) { 101250199Sgrehan return (NULL); 102250199Sgrehan } 103250199Sgrehan 104250199Sgrehan return (net_dev); 105250199Sgrehan} 106250199Sgrehan 107250199Sgrehan/* 108250199Sgrehan * 109250199Sgrehan */ 110250199Sgrehanstatic inline netvsc_dev * 111250199Sgrehanhv_nv_get_inbound_net_device(struct hv_device *device) 112250199Sgrehan{ 113250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 114250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 115250199Sgrehan 116250199Sgrehan if (net_dev == NULL) { 117250199Sgrehan return (net_dev); 118250199Sgrehan } 119250199Sgrehan /* 120250199Sgrehan * When the device is being destroyed; we only 121250199Sgrehan * permit incoming packets if and only if there 122250199Sgrehan * are outstanding sends. 123250199Sgrehan */ 124301912Ssephe if (net_dev->destroy) { 125250199Sgrehan return (NULL); 126250199Sgrehan } 127250199Sgrehan 128250199Sgrehan return (net_dev); 129250199Sgrehan} 130250199Sgrehan 131285236Swhuint 132285236Swhuhv_nv_get_next_send_section(netvsc_dev *net_dev) 133285236Swhu{ 134285236Swhu unsigned long bitsmap_words = net_dev->bitsmap_words; 135285236Swhu unsigned long *bitsmap = net_dev->send_section_bitsmap; 136285236Swhu unsigned long idx; 137285236Swhu int ret = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX; 138285236Swhu int i; 139285236Swhu 140285236Swhu for (i = 0; i < bitsmap_words; i++) { 141301857Ssephe idx = ffsl(~bitsmap[i]); 142285236Swhu if (0 == idx) 143285236Swhu continue; 144285236Swhu 145285236Swhu idx--; 146301857Ssephe KASSERT(i * BITS_PER_LONG + idx < net_dev->send_section_count, 147301857Ssephe ("invalid i %d and idx %lu", i, idx)); 148285236Swhu 149301857Ssephe if (atomic_testandset_long(&bitsmap[i], idx)) 150285236Swhu continue; 151285236Swhu 152285236Swhu ret = i * BITS_PER_LONG + idx; 153285236Swhu break; 154285236Swhu } 155285236Swhu 156285236Swhu return (ret); 157285236Swhu} 158285236Swhu 159250199Sgrehan/* 160250199Sgrehan * Net VSC initialize receive buffer with net VSP 161250199Sgrehan * 162250199Sgrehan * Net VSP: Network virtual services client, also known as the 163250199Sgrehan * Hyper-V extensible switch and the synthetic data path. 164250199Sgrehan */ 165250199Sgrehanstatic int 166250199Sgrehanhv_nv_init_rx_buffer_with_net_vsp(struct hv_device *device) 167250199Sgrehan{ 168250199Sgrehan netvsc_dev *net_dev; 169250199Sgrehan nvsp_msg *init_pkt; 170250199Sgrehan int ret = 0; 171250199Sgrehan 172250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 173250199Sgrehan if (!net_dev) { 174250199Sgrehan return (ENODEV); 175250199Sgrehan } 176250199Sgrehan 177285236Swhu net_dev->rx_buf = contigmalloc(net_dev->rx_buf_size, M_NETVSC, 178250199Sgrehan M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); 179250199Sgrehan 180250199Sgrehan /* 181250199Sgrehan * Establish the GPADL handle for this buffer on this channel. 182250199Sgrehan * Note: This call uses the vmbus connection rather than the 183250199Sgrehan * channel to establish the gpadl handle. 184250199Sgrehan * GPADL: Guest physical address descriptor list. 185250199Sgrehan */ 186250199Sgrehan ret = hv_vmbus_channel_establish_gpadl( 187250199Sgrehan device->channel, net_dev->rx_buf, 188250199Sgrehan net_dev->rx_buf_size, &net_dev->rx_buf_gpadl_handle); 189250199Sgrehan if (ret != 0) { 190250199Sgrehan goto cleanup; 191250199Sgrehan } 192250199Sgrehan 193250199Sgrehan /* sema_wait(&ext->channel_init_sema); KYS CHECK */ 194250199Sgrehan 195250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 196250199Sgrehan init_pkt = &net_dev->channel_init_packet; 197250199Sgrehan 198250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 199250199Sgrehan 200250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_rx_buf; 201250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 202250199Sgrehan net_dev->rx_buf_gpadl_handle; 203250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 204250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 205250199Sgrehan 206250199Sgrehan /* Send the gpadl notification request */ 207250199Sgrehan 208250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 209266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 210250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 211250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 212250199Sgrehan if (ret != 0) { 213250199Sgrehan goto cleanup; 214250199Sgrehan } 215250199Sgrehan 216250199Sgrehan sema_wait(&net_dev->channel_init_sema); 217250199Sgrehan 218250199Sgrehan /* Check the response */ 219250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.status 220250199Sgrehan != nvsp_status_success) { 221250199Sgrehan ret = EINVAL; 222250199Sgrehan goto cleanup; 223250199Sgrehan } 224250199Sgrehan 225250199Sgrehan net_dev->rx_section_count = 226250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.num_sections; 227250199Sgrehan 228250199Sgrehan net_dev->rx_sections = malloc(net_dev->rx_section_count * 229301859Ssephe sizeof(nvsp_1_rx_buf_section), M_NETVSC, M_WAITOK); 230250199Sgrehan memcpy(net_dev->rx_sections, 231250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf_complete.sections, 232250199Sgrehan net_dev->rx_section_count * sizeof(nvsp_1_rx_buf_section)); 233250199Sgrehan 234250199Sgrehan 235250199Sgrehan /* 236250199Sgrehan * For first release, there should only be 1 section that represents 237250199Sgrehan * the entire receive buffer 238250199Sgrehan */ 239250199Sgrehan if (net_dev->rx_section_count != 1 240250199Sgrehan || net_dev->rx_sections->offset != 0) { 241250199Sgrehan ret = EINVAL; 242250199Sgrehan goto cleanup; 243250199Sgrehan } 244250199Sgrehan 245250199Sgrehan goto exit; 246250199Sgrehan 247250199Sgrehancleanup: 248250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 249250199Sgrehan 250250199Sgrehanexit: 251250199Sgrehan return (ret); 252250199Sgrehan} 253250199Sgrehan 254250199Sgrehan/* 255250199Sgrehan * Net VSC initialize send buffer with net VSP 256250199Sgrehan */ 257250199Sgrehanstatic int 258250199Sgrehanhv_nv_init_send_buffer_with_net_vsp(struct hv_device *device) 259250199Sgrehan{ 260250199Sgrehan netvsc_dev *net_dev; 261250199Sgrehan nvsp_msg *init_pkt; 262250199Sgrehan int ret = 0; 263250199Sgrehan 264250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 265250199Sgrehan if (!net_dev) { 266250199Sgrehan return (ENODEV); 267250199Sgrehan } 268250199Sgrehan 269285236Swhu net_dev->send_buf = contigmalloc(net_dev->send_buf_size, M_NETVSC, 270250199Sgrehan M_ZERO, 0UL, BUS_SPACE_MAXADDR, PAGE_SIZE, 0); 271250199Sgrehan if (net_dev->send_buf == NULL) { 272250199Sgrehan ret = ENOMEM; 273250199Sgrehan goto cleanup; 274250199Sgrehan } 275250199Sgrehan 276250199Sgrehan /* 277250199Sgrehan * Establish the gpadl handle for this buffer on this channel. 278250199Sgrehan * Note: This call uses the vmbus connection rather than the 279250199Sgrehan * channel to establish the gpadl handle. 280250199Sgrehan */ 281250199Sgrehan ret = hv_vmbus_channel_establish_gpadl(device->channel, 282285236Swhu net_dev->send_buf, net_dev->send_buf_size, 283250199Sgrehan &net_dev->send_buf_gpadl_handle); 284250199Sgrehan if (ret != 0) { 285250199Sgrehan goto cleanup; 286250199Sgrehan } 287250199Sgrehan 288250199Sgrehan /* Notify the NetVsp of the gpadl handle */ 289250199Sgrehan 290250199Sgrehan init_pkt = &net_dev->channel_init_packet; 291250199Sgrehan 292250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 293250199Sgrehan 294250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_send_buf; 295250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.gpadl_handle = 296250199Sgrehan net_dev->send_buf_gpadl_handle; 297250199Sgrehan init_pkt->msgs.vers_1_msgs.send_rx_buf.id = 298250199Sgrehan NETVSC_SEND_BUFFER_ID; 299250199Sgrehan 300250199Sgrehan /* Send the gpadl notification request */ 301250199Sgrehan 302250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 303285236Swhu sizeof(nvsp_msg), (uint64_t)init_pkt, 304250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 305250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 306250199Sgrehan if (ret != 0) { 307250199Sgrehan goto cleanup; 308250199Sgrehan } 309250199Sgrehan 310250199Sgrehan sema_wait(&net_dev->channel_init_sema); 311250199Sgrehan 312250199Sgrehan /* Check the response */ 313250199Sgrehan if (init_pkt->msgs.vers_1_msgs.send_send_buf_complete.status 314250199Sgrehan != nvsp_status_success) { 315250199Sgrehan ret = EINVAL; 316250199Sgrehan goto cleanup; 317250199Sgrehan } 318250199Sgrehan 319250199Sgrehan net_dev->send_section_size = 320250199Sgrehan init_pkt->msgs.vers_1_msgs.send_send_buf_complete.section_size; 321285236Swhu net_dev->send_section_count = 322285236Swhu net_dev->send_buf_size / net_dev->send_section_size; 323285236Swhu net_dev->bitsmap_words = howmany(net_dev->send_section_count, 324285236Swhu BITS_PER_LONG); 325285236Swhu net_dev->send_section_bitsmap = 326285236Swhu malloc(net_dev->bitsmap_words * sizeof(long), M_NETVSC, 327301859Ssephe M_WAITOK | M_ZERO); 328250199Sgrehan 329250199Sgrehan goto exit; 330250199Sgrehan 331250199Sgrehancleanup: 332250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 333250199Sgrehan 334250199Sgrehanexit: 335250199Sgrehan return (ret); 336250199Sgrehan} 337250199Sgrehan 338250199Sgrehan/* 339250199Sgrehan * Net VSC destroy receive buffer 340250199Sgrehan */ 341250199Sgrehanstatic int 342250199Sgrehanhv_nv_destroy_rx_buffer(netvsc_dev *net_dev) 343250199Sgrehan{ 344250199Sgrehan nvsp_msg *revoke_pkt; 345250199Sgrehan int ret = 0; 346250199Sgrehan 347250199Sgrehan /* 348250199Sgrehan * If we got a section count, it means we received a 349250199Sgrehan * send_rx_buf_complete msg 350250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 351250199Sgrehan * we need to send a revoke msg here 352250199Sgrehan */ 353250199Sgrehan if (net_dev->rx_section_count) { 354250199Sgrehan /* Send the revoke receive buffer */ 355250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 356250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 357250199Sgrehan 358250199Sgrehan revoke_pkt->hdr.msg_type = nvsp_msg_1_type_revoke_rx_buf; 359250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_rx_buf.id = 360250199Sgrehan NETVSC_RECEIVE_BUFFER_ID; 361250199Sgrehan 362250199Sgrehan ret = hv_vmbus_channel_send_packet(net_dev->dev->channel, 363250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 364266794Smarius (uint64_t)(uintptr_t)revoke_pkt, 365250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 366250199Sgrehan 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 } 375250199Sgrehan 376250199Sgrehan /* Tear down the gpadl on the vsp end */ 377250199Sgrehan if (net_dev->rx_buf_gpadl_handle) { 378250199Sgrehan ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel, 379250199Sgrehan net_dev->rx_buf_gpadl_handle); 380250199Sgrehan /* 381250199Sgrehan * If we failed here, we might as well return and have a leak 382250199Sgrehan * rather than continue and a bugchk 383250199Sgrehan */ 384250199Sgrehan if (ret != 0) { 385250199Sgrehan return (ret); 386250199Sgrehan } 387250199Sgrehan net_dev->rx_buf_gpadl_handle = 0; 388250199Sgrehan } 389250199Sgrehan 390250199Sgrehan if (net_dev->rx_buf) { 391250199Sgrehan /* Free up the receive buffer */ 392285236Swhu contigfree(net_dev->rx_buf, net_dev->rx_buf_size, M_NETVSC); 393250199Sgrehan net_dev->rx_buf = NULL; 394250199Sgrehan } 395250199Sgrehan 396250199Sgrehan if (net_dev->rx_sections) { 397285236Swhu free(net_dev->rx_sections, M_NETVSC); 398250199Sgrehan net_dev->rx_sections = NULL; 399250199Sgrehan net_dev->rx_section_count = 0; 400250199Sgrehan } 401250199Sgrehan 402250199Sgrehan return (ret); 403250199Sgrehan} 404250199Sgrehan 405250199Sgrehan/* 406250199Sgrehan * Net VSC destroy send buffer 407250199Sgrehan */ 408250199Sgrehanstatic int 409250199Sgrehanhv_nv_destroy_send_buffer(netvsc_dev *net_dev) 410250199Sgrehan{ 411250199Sgrehan nvsp_msg *revoke_pkt; 412250199Sgrehan int ret = 0; 413250199Sgrehan 414250199Sgrehan /* 415250199Sgrehan * If we got a section count, it means we received a 416250199Sgrehan * send_rx_buf_complete msg 417250199Sgrehan * (ie sent nvsp_msg_1_type_send_rx_buf msg) therefore, 418250199Sgrehan * we need to send a revoke msg here 419250199Sgrehan */ 420250199Sgrehan if (net_dev->send_section_size) { 421250199Sgrehan /* Send the revoke send buffer */ 422250199Sgrehan revoke_pkt = &net_dev->revoke_packet; 423250199Sgrehan memset(revoke_pkt, 0, sizeof(nvsp_msg)); 424250199Sgrehan 425250199Sgrehan revoke_pkt->hdr.msg_type = 426250199Sgrehan nvsp_msg_1_type_revoke_send_buf; 427250199Sgrehan revoke_pkt->msgs.vers_1_msgs.revoke_send_buf.id = 428250199Sgrehan NETVSC_SEND_BUFFER_ID; 429250199Sgrehan 430250199Sgrehan ret = hv_vmbus_channel_send_packet(net_dev->dev->channel, 431250199Sgrehan revoke_pkt, sizeof(nvsp_msg), 432266794Smarius (uint64_t)(uintptr_t)revoke_pkt, 433250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 434250199Sgrehan /* 435250199Sgrehan * If we failed here, we might as well return and have a leak 436250199Sgrehan * rather than continue and a bugchk 437250199Sgrehan */ 438250199Sgrehan if (ret != 0) { 439250199Sgrehan return (ret); 440250199Sgrehan } 441250199Sgrehan } 442250199Sgrehan 443250199Sgrehan /* Tear down the gpadl on the vsp end */ 444250199Sgrehan if (net_dev->send_buf_gpadl_handle) { 445250199Sgrehan ret = hv_vmbus_channel_teardown_gpdal(net_dev->dev->channel, 446250199Sgrehan net_dev->send_buf_gpadl_handle); 447250199Sgrehan 448250199Sgrehan /* 449250199Sgrehan * If we failed here, we might as well return and have a leak 450250199Sgrehan * rather than continue and a bugchk 451250199Sgrehan */ 452250199Sgrehan if (ret != 0) { 453250199Sgrehan return (ret); 454250199Sgrehan } 455250199Sgrehan net_dev->send_buf_gpadl_handle = 0; 456250199Sgrehan } 457250199Sgrehan 458250199Sgrehan if (net_dev->send_buf) { 459250199Sgrehan /* Free up the receive buffer */ 460285236Swhu contigfree(net_dev->send_buf, net_dev->send_buf_size, M_NETVSC); 461250199Sgrehan net_dev->send_buf = NULL; 462250199Sgrehan } 463250199Sgrehan 464285236Swhu if (net_dev->send_section_bitsmap) { 465285236Swhu free(net_dev->send_section_bitsmap, M_NETVSC); 466285236Swhu } 467285236Swhu 468250199Sgrehan return (ret); 469250199Sgrehan} 470250199Sgrehan 471250199Sgrehan 472250199Sgrehan/* 473250199Sgrehan * Attempt to negotiate the caller-specified NVSP version 474250199Sgrehan * 475250199Sgrehan * For NVSP v2, Server 2008 R2 does not set 476250199Sgrehan * init_pkt->msgs.init_msgs.init_compl.negotiated_prot_vers 477250199Sgrehan * to the negotiated version, so we cannot rely on that. 478250199Sgrehan */ 479250199Sgrehanstatic int 480250199Sgrehanhv_nv_negotiate_nvsp_protocol(struct hv_device *device, netvsc_dev *net_dev, 481285236Swhu uint32_t nvsp_ver) 482250199Sgrehan{ 483250199Sgrehan nvsp_msg *init_pkt; 484250199Sgrehan int ret; 485250199Sgrehan 486250199Sgrehan init_pkt = &net_dev->channel_init_packet; 487250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 488250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_type_init; 489250199Sgrehan 490250199Sgrehan /* 491250199Sgrehan * Specify parameter as the only acceptable protocol version 492250199Sgrehan */ 493250199Sgrehan init_pkt->msgs.init_msgs.init.p1.protocol_version = nvsp_ver; 494250199Sgrehan init_pkt->msgs.init_msgs.init.protocol_version_2 = nvsp_ver; 495250199Sgrehan 496250199Sgrehan /* Send the init request */ 497250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 498266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 499250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 500250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 501250199Sgrehan if (ret != 0) 502250199Sgrehan return (-1); 503250199Sgrehan 504250199Sgrehan sema_wait(&net_dev->channel_init_sema); 505250199Sgrehan 506250199Sgrehan if (init_pkt->msgs.init_msgs.init_compl.status != nvsp_status_success) 507250199Sgrehan return (EINVAL); 508250199Sgrehan 509250199Sgrehan return (0); 510250199Sgrehan} 511250199Sgrehan 512250199Sgrehan/* 513250199Sgrehan * Send NDIS version 2 config packet containing MTU. 514250199Sgrehan * 515250199Sgrehan * Not valid for NDIS version 1. 516250199Sgrehan */ 517250199Sgrehanstatic int 518250199Sgrehanhv_nv_send_ndis_config(struct hv_device *device, uint32_t mtu) 519250199Sgrehan{ 520250199Sgrehan netvsc_dev *net_dev; 521250199Sgrehan nvsp_msg *init_pkt; 522250199Sgrehan int ret; 523250199Sgrehan 524250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 525250199Sgrehan if (!net_dev) 526250199Sgrehan return (-ENODEV); 527250199Sgrehan 528250199Sgrehan /* 529250199Sgrehan * Set up configuration packet, write MTU 530250199Sgrehan * Indicate we are capable of handling VLAN tags 531250199Sgrehan */ 532250199Sgrehan init_pkt = &net_dev->channel_init_packet; 533250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 534250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_2_type_send_ndis_config; 535250199Sgrehan init_pkt->msgs.vers_2_msgs.send_ndis_config.mtu = mtu; 536250199Sgrehan init_pkt-> 537250199Sgrehan msgs.vers_2_msgs.send_ndis_config.capabilities.u1.u2.ieee8021q 538250199Sgrehan = 1; 539250199Sgrehan 540250199Sgrehan /* Send the configuration packet */ 541250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 542266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 543250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 544250199Sgrehan if (ret != 0) 545250199Sgrehan return (-EINVAL); 546250199Sgrehan 547250199Sgrehan return (0); 548250199Sgrehan} 549250199Sgrehan 550250199Sgrehan/* 551250199Sgrehan * Net VSC connect to VSP 552250199Sgrehan */ 553250199Sgrehanstatic int 554250199Sgrehanhv_nv_connect_to_vsp(struct hv_device *device) 555250199Sgrehan{ 556250199Sgrehan netvsc_dev *net_dev; 557250199Sgrehan nvsp_msg *init_pkt; 558250199Sgrehan uint32_t ndis_version; 559285236Swhu uint32_t protocol_list[] = { NVSP_PROTOCOL_VERSION_1, 560285236Swhu NVSP_PROTOCOL_VERSION_2, 561285236Swhu NVSP_PROTOCOL_VERSION_4, 562285236Swhu NVSP_PROTOCOL_VERSION_5 }; 563285236Swhu int i; 564285236Swhu int protocol_number = nitems(protocol_list); 565250199Sgrehan int ret = 0; 566250199Sgrehan device_t dev = device->device; 567250199Sgrehan hn_softc_t *sc = device_get_softc(dev); 568250199Sgrehan struct ifnet *ifp = sc->arpcom.ac_ifp; 569250199Sgrehan 570250199Sgrehan net_dev = hv_nv_get_outbound_net_device(device); 571250199Sgrehan if (!net_dev) { 572250199Sgrehan return (ENODEV); 573250199Sgrehan } 574250199Sgrehan 575250199Sgrehan /* 576285236Swhu * Negotiate the NVSP version. Try the latest NVSP first. 577250199Sgrehan */ 578285236Swhu for (i = protocol_number - 1; i >= 0; i--) { 579285236Swhu if (hv_nv_negotiate_nvsp_protocol(device, net_dev, 580285236Swhu protocol_list[i]) == 0) { 581285236Swhu net_dev->nvsp_version = protocol_list[i]; 582285236Swhu if (bootverbose) 583285236Swhu device_printf(dev, "Netvsc: got version 0x%x\n", 584285236Swhu net_dev->nvsp_version); 585285236Swhu break; 586250199Sgrehan } 587250199Sgrehan } 588250199Sgrehan 589285236Swhu if (i < 0) { 590285236Swhu if (bootverbose) 591285236Swhu device_printf(dev, "failed to negotiate a valid " 592285236Swhu "protocol.\n"); 593285236Swhu return (EPROTO); 594285236Swhu } 595285236Swhu 596250199Sgrehan /* 597250199Sgrehan * Set the MTU if supported by this NVSP protocol version 598250199Sgrehan * This needs to be right after the NVSP init message per Haiyang 599250199Sgrehan */ 600285236Swhu if (net_dev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) 601250199Sgrehan ret = hv_nv_send_ndis_config(device, ifp->if_mtu); 602250199Sgrehan 603250199Sgrehan /* 604250199Sgrehan * Send the NDIS version 605250199Sgrehan */ 606250199Sgrehan init_pkt = &net_dev->channel_init_packet; 607250199Sgrehan 608250199Sgrehan memset(init_pkt, 0, sizeof(nvsp_msg)); 609250199Sgrehan 610285236Swhu if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_4) { 611285236Swhu ndis_version = NDIS_VERSION_6_1; 612285236Swhu } else { 613285236Swhu ndis_version = NDIS_VERSION_6_30; 614285236Swhu } 615250199Sgrehan 616250199Sgrehan init_pkt->hdr.msg_type = nvsp_msg_1_type_send_ndis_vers; 617250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_major_vers = 618250199Sgrehan (ndis_version & 0xFFFF0000) >> 16; 619250199Sgrehan init_pkt->msgs.vers_1_msgs.send_ndis_vers.ndis_minor_vers = 620250199Sgrehan ndis_version & 0xFFFF; 621250199Sgrehan 622250199Sgrehan /* Send the init request */ 623250199Sgrehan 624250199Sgrehan ret = hv_vmbus_channel_send_packet(device->channel, init_pkt, 625266794Smarius sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt, 626250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 0); 627250199Sgrehan if (ret != 0) { 628250199Sgrehan goto cleanup; 629250199Sgrehan } 630250199Sgrehan /* 631250199Sgrehan * TODO: BUGBUG - We have to wait for the above msg since the netvsp 632250199Sgrehan * uses KMCL which acknowledges packet (completion packet) 633250199Sgrehan * since our Vmbus always set the 634250199Sgrehan * HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED flag 635250199Sgrehan */ 636250199Sgrehan /* sema_wait(&NetVscChannel->channel_init_sema); */ 637250199Sgrehan 638250199Sgrehan /* Post the big receive buffer to NetVSP */ 639295789Ssephe if (net_dev->nvsp_version <= NVSP_PROTOCOL_VERSION_2) 640295789Ssephe net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; 641295789Ssephe else 642295789Ssephe net_dev->rx_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; 643295789Ssephe net_dev->send_buf_size = NETVSC_SEND_BUFFER_SIZE; 644295789Ssephe 645250199Sgrehan ret = hv_nv_init_rx_buffer_with_net_vsp(device); 646250199Sgrehan if (ret == 0) 647250199Sgrehan ret = hv_nv_init_send_buffer_with_net_vsp(device); 648250199Sgrehan 649250199Sgrehancleanup: 650250199Sgrehan return (ret); 651250199Sgrehan} 652250199Sgrehan 653250199Sgrehan/* 654250199Sgrehan * Net VSC disconnect from VSP 655250199Sgrehan */ 656250199Sgrehanstatic void 657250199Sgrehanhv_nv_disconnect_from_vsp(netvsc_dev *net_dev) 658250199Sgrehan{ 659250199Sgrehan hv_nv_destroy_rx_buffer(net_dev); 660250199Sgrehan hv_nv_destroy_send_buffer(net_dev); 661250199Sgrehan} 662250199Sgrehan 663250199Sgrehan/* 664301943Ssephe * Callback handler for subchannel offer 665301943Ssephe * @@param context new subchannel 666301943Ssephe */ 667301943Ssephestatic void 668301943Ssephehv_nv_subchan_callback(void *xchan) 669301943Ssephe{ 670301943Ssephe struct hv_vmbus_channel *chan = xchan; 671301943Ssephe netvsc_dev *net_dev; 672301943Ssephe uint16_t chn_index = chan->offer_msg.offer.sub_channel_index; 673301943Ssephe struct hv_device *device = chan->device; 674301943Ssephe hn_softc_t *sc = device_get_softc(device->device); 675301943Ssephe int ret; 676301943Ssephe 677301943Ssephe net_dev = sc->net_dev; 678301943Ssephe 679301943Ssephe if (chn_index >= net_dev->num_channel) { 680301943Ssephe /* Would this ever happen? */ 681301943Ssephe return; 682301943Ssephe } 683301943Ssephe netvsc_subchan_callback(sc, chan); 684301943Ssephe 685301943Ssephe chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK); 686301943Ssephe ret = hv_vmbus_channel_open(chan, NETVSC_DEVICE_RING_BUFFER_SIZE, 687301943Ssephe NETVSC_DEVICE_RING_BUFFER_SIZE, NULL, 0, 688301943Ssephe hv_nv_on_channel_callback, chan); 689301943Ssephe} 690301943Ssephe 691301943Ssephe/* 692250199Sgrehan * Net VSC on device add 693250199Sgrehan * 694250199Sgrehan * Callback when the device belonging to this driver is added 695250199Sgrehan */ 696250199Sgrehannetvsc_dev * 697250199Sgrehanhv_nv_on_device_add(struct hv_device *device, void *additional_info) 698250199Sgrehan{ 699301918Ssephe struct hv_vmbus_channel *chan = device->channel; 700250199Sgrehan netvsc_dev *net_dev; 701285236Swhu int ret = 0; 702250199Sgrehan 703250199Sgrehan net_dev = hv_nv_alloc_net_device(device); 704301918Ssephe if (net_dev == NULL) 705301918Ssephe return NULL; 706250199Sgrehan 707250199Sgrehan /* Initialize the NetVSC channel extension */ 708250199Sgrehan 709250199Sgrehan sema_init(&net_dev->channel_init_sema, 0, "netdev_sema"); 710250199Sgrehan 711301918Ssephe chan->hv_chan_rdbuf = malloc(NETVSC_PACKET_SIZE, M_NETVSC, M_WAITOK); 712301918Ssephe 713250199Sgrehan /* 714250199Sgrehan * Open the channel 715250199Sgrehan */ 716301918Ssephe ret = hv_vmbus_channel_open(chan, 717250199Sgrehan NETVSC_DEVICE_RING_BUFFER_SIZE, NETVSC_DEVICE_RING_BUFFER_SIZE, 718301918Ssephe NULL, 0, hv_nv_on_channel_callback, chan); 719301918Ssephe if (ret != 0) { 720301918Ssephe free(chan->hv_chan_rdbuf, M_NETVSC); 721250199Sgrehan goto cleanup; 722301918Ssephe } 723301943Ssephe chan->sc_creation_callback = hv_nv_subchan_callback; 724250199Sgrehan 725250199Sgrehan /* 726250199Sgrehan * Connect with the NetVsp 727250199Sgrehan */ 728250199Sgrehan ret = hv_nv_connect_to_vsp(device); 729250199Sgrehan if (ret != 0) 730250199Sgrehan goto close; 731250199Sgrehan 732250199Sgrehan return (net_dev); 733250199Sgrehan 734250199Sgrehanclose: 735250199Sgrehan /* Now, we can close the channel safely */ 736301918Ssephe free(chan->hv_chan_rdbuf, M_NETVSC); 737301918Ssephe hv_vmbus_channel_close(chan); 738250199Sgrehan 739250199Sgrehancleanup: 740250199Sgrehan /* 741250199Sgrehan * Free the packet buffers on the netvsc device packet queue. 742250199Sgrehan * Release other resources. 743250199Sgrehan */ 744301952Ssephe sema_destroy(&net_dev->channel_init_sema); 745301952Ssephe free(net_dev, M_NETVSC); 746250199Sgrehan 747250199Sgrehan return (NULL); 748250199Sgrehan} 749250199Sgrehan 750250199Sgrehan/* 751250199Sgrehan * Net VSC on device remove 752250199Sgrehan */ 753250199Sgrehanint 754250199Sgrehanhv_nv_on_device_remove(struct hv_device *device, boolean_t destroy_channel) 755250199Sgrehan{ 756250199Sgrehan hn_softc_t *sc = device_get_softc(device->device); 757250199Sgrehan netvsc_dev *net_dev = sc->net_dev;; 758250199Sgrehan 759250199Sgrehan /* Stop outbound traffic ie sends and receives completions */ 760250199Sgrehan net_dev->destroy = TRUE; 761250199Sgrehan 762250199Sgrehan hv_nv_disconnect_from_vsp(net_dev); 763250199Sgrehan 764250199Sgrehan /* At this point, no one should be accessing net_dev except in here */ 765250199Sgrehan 766250199Sgrehan /* Now, we can close the channel safely */ 767250199Sgrehan 768250199Sgrehan if (!destroy_channel) { 769250199Sgrehan device->channel->state = 770250199Sgrehan HV_CHANNEL_CLOSING_NONDESTRUCTIVE_STATE; 771250199Sgrehan } 772250199Sgrehan 773301918Ssephe free(device->channel->hv_chan_rdbuf, M_NETVSC); 774250199Sgrehan hv_vmbus_channel_close(device->channel); 775250199Sgrehan 776250199Sgrehan sema_destroy(&net_dev->channel_init_sema); 777285236Swhu free(net_dev, M_NETVSC); 778250199Sgrehan 779250199Sgrehan return (0); 780250199Sgrehan} 781250199Sgrehan 782250199Sgrehan/* 783250199Sgrehan * Net VSC on send completion 784250199Sgrehan */ 785285236Swhustatic void 786285236Swhuhv_nv_on_send_completion(netvsc_dev *net_dev, 787301943Ssephe struct hv_device *device, struct hv_vmbus_channel *chan, 788301943Ssephe hv_vm_packet_descriptor *pkt) 789250199Sgrehan{ 790250199Sgrehan nvsp_msg *nvsp_msg_pkt; 791250199Sgrehan netvsc_packet *net_vsc_pkt; 792250199Sgrehan 793250199Sgrehan nvsp_msg_pkt = 794250199Sgrehan (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); 795250199Sgrehan 796250199Sgrehan if (nvsp_msg_pkt->hdr.msg_type == nvsp_msg_type_init_complete 797250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 798250199Sgrehan == nvsp_msg_1_type_send_rx_buf_complete 799250199Sgrehan || nvsp_msg_pkt->hdr.msg_type 800301943Ssephe == nvsp_msg_1_type_send_send_buf_complete 801301943Ssephe || nvsp_msg_pkt->hdr.msg_type 802301943Ssephe == nvsp_msg5_type_subchannel) { 803250199Sgrehan /* Copy the response back */ 804250199Sgrehan memcpy(&net_dev->channel_init_packet, nvsp_msg_pkt, 805285236Swhu sizeof(nvsp_msg)); 806250199Sgrehan sema_post(&net_dev->channel_init_sema); 807250199Sgrehan } else if (nvsp_msg_pkt->hdr.msg_type == 808285236Swhu nvsp_msg_1_type_send_rndis_pkt_complete) { 809250199Sgrehan /* Get the send context */ 810250199Sgrehan net_vsc_pkt = 811250199Sgrehan (netvsc_packet *)(unsigned long)pkt->transaction_id; 812285236Swhu if (NULL != net_vsc_pkt) { 813285236Swhu if (net_vsc_pkt->send_buf_section_idx != 814285236Swhu NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) { 815301857Ssephe u_long mask; 816301857Ssephe int idx; 817301857Ssephe 818301857Ssephe idx = net_vsc_pkt->send_buf_section_idx / 819301857Ssephe BITS_PER_LONG; 820301857Ssephe KASSERT(idx < net_dev->bitsmap_words, 821301857Ssephe ("invalid section index %u", 822301857Ssephe net_vsc_pkt->send_buf_section_idx)); 823301857Ssephe mask = 1UL << 824301857Ssephe (net_vsc_pkt->send_buf_section_idx % 825301857Ssephe BITS_PER_LONG); 826301857Ssephe 827301857Ssephe KASSERT(net_dev->send_section_bitsmap[idx] & 828301857Ssephe mask, 829301857Ssephe ("index bitmap 0x%lx, section index %u, " 830301857Ssephe "bitmap idx %d, bitmask 0x%lx", 831301857Ssephe net_dev->send_section_bitsmap[idx], 832301857Ssephe net_vsc_pkt->send_buf_section_idx, 833301857Ssephe idx, mask)); 834301857Ssephe atomic_clear_long( 835301857Ssephe &net_dev->send_section_bitsmap[idx], mask); 836285236Swhu } 837285236Swhu 838285236Swhu /* Notify the layer above us */ 839301943Ssephe net_vsc_pkt->compl.send.on_send_completion(chan, 840285236Swhu net_vsc_pkt->compl.send.send_completion_context); 841250199Sgrehan 842285236Swhu } 843250199Sgrehan } 844250199Sgrehan} 845250199Sgrehan 846250199Sgrehan/* 847250199Sgrehan * Net VSC on send 848250199Sgrehan * Sends a packet on the specified Hyper-V device. 849250199Sgrehan * Returns 0 on success, non-zero on failure. 850250199Sgrehan */ 851250199Sgrehanint 852301912Ssephehv_nv_on_send(struct hv_vmbus_channel *chan, netvsc_packet *pkt) 853250199Sgrehan{ 854250199Sgrehan nvsp_msg send_msg; 855250199Sgrehan int ret; 856250199Sgrehan 857250199Sgrehan send_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt; 858250199Sgrehan if (pkt->is_data_pkt) { 859250199Sgrehan /* 0 is RMC_DATA */ 860250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 0; 861250199Sgrehan } else { 862250199Sgrehan /* 1 is RMC_CONTROL */ 863250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.chan_type = 1; 864250199Sgrehan } 865250199Sgrehan 866250199Sgrehan send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_idx = 867285236Swhu pkt->send_buf_section_idx; 868285236Swhu send_msg.msgs.vers_1_msgs.send_rndis_pkt.send_buf_section_size = 869285236Swhu pkt->send_buf_section_size; 870250199Sgrehan 871250199Sgrehan if (pkt->page_buf_count) { 872301912Ssephe ret = hv_vmbus_channel_send_packet_pagebuffer(chan, 873250199Sgrehan pkt->page_buffers, pkt->page_buf_count, 874266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt); 875250199Sgrehan } else { 876301912Ssephe ret = hv_vmbus_channel_send_packet(chan, 877266794Smarius &send_msg, sizeof(nvsp_msg), (uint64_t)(uintptr_t)pkt, 878250199Sgrehan HV_VMBUS_PACKET_TYPE_DATA_IN_BAND, 879250199Sgrehan HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); 880250199Sgrehan } 881250199Sgrehan 882250199Sgrehan return (ret); 883250199Sgrehan} 884250199Sgrehan 885250199Sgrehan/* 886250199Sgrehan * Net VSC on receive 887250199Sgrehan * 888250199Sgrehan * In the FreeBSD Hyper-V virtual world, this function deals exclusively 889250199Sgrehan * with virtual addresses. 890250199Sgrehan */ 891285236Swhustatic void 892285236Swhuhv_nv_on_receive(netvsc_dev *net_dev, struct hv_device *device, 893301912Ssephe struct hv_vmbus_channel *chan, hv_vm_packet_descriptor *pkt) 894250199Sgrehan{ 895250199Sgrehan hv_vm_transfer_page_packet_header *vm_xfer_page_pkt; 896250199Sgrehan nvsp_msg *nvsp_msg_pkt; 897285236Swhu netvsc_packet vsc_pkt; 898285236Swhu netvsc_packet *net_vsc_pkt = &vsc_pkt; 899285236Swhu device_t dev = device->device; 900250199Sgrehan int count = 0; 901250199Sgrehan int i = 0; 902285236Swhu int status = nvsp_status_success; 903250199Sgrehan 904250199Sgrehan /* 905250199Sgrehan * All inbound packets other than send completion should be 906250199Sgrehan * xfer page packet. 907250199Sgrehan */ 908285236Swhu if (pkt->type != HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES) { 909285236Swhu device_printf(dev, "packet type %d is invalid!\n", pkt->type); 910250199Sgrehan return; 911285236Swhu } 912250199Sgrehan 913250199Sgrehan nvsp_msg_pkt = (nvsp_msg *)((unsigned long)pkt 914250199Sgrehan + (pkt->data_offset8 << 3)); 915250199Sgrehan 916250199Sgrehan /* Make sure this is a valid nvsp packet */ 917285236Swhu if (nvsp_msg_pkt->hdr.msg_type != nvsp_msg_1_type_send_rndis_pkt) { 918285236Swhu device_printf(dev, "packet hdr type %d is invalid!\n", 919285236Swhu pkt->type); 920250199Sgrehan return; 921285236Swhu } 922250199Sgrehan 923250199Sgrehan vm_xfer_page_pkt = (hv_vm_transfer_page_packet_header *)pkt; 924250199Sgrehan 925285236Swhu if (vm_xfer_page_pkt->transfer_page_set_id != 926285236Swhu NETVSC_RECEIVE_BUFFER_ID) { 927285236Swhu device_printf(dev, "transfer_page_set_id %d is invalid!\n", 928285236Swhu vm_xfer_page_pkt->transfer_page_set_id); 929250199Sgrehan return; 930250199Sgrehan } 931250199Sgrehan 932285236Swhu count = vm_xfer_page_pkt->range_count; 933285236Swhu net_vsc_pkt->device = device; 934250199Sgrehan 935285236Swhu /* Each range represents 1 RNDIS pkt that contains 1 Ethernet frame */ 936285236Swhu for (i = 0; i < count; i++) { 937285236Swhu net_vsc_pkt->status = nvsp_status_success; 938285236Swhu net_vsc_pkt->data = (void *)((unsigned long)net_dev->rx_buf + 939285236Swhu vm_xfer_page_pkt->ranges[i].byte_offset); 940285236Swhu net_vsc_pkt->tot_data_buf_len = 941285236Swhu vm_xfer_page_pkt->ranges[i].byte_count; 942250199Sgrehan 943301912Ssephe hv_rf_on_receive(net_dev, device, chan, net_vsc_pkt); 944285236Swhu if (net_vsc_pkt->status != nvsp_status_success) { 945285236Swhu status = nvsp_status_failure; 946285236Swhu } 947250199Sgrehan } 948285236Swhu 949250199Sgrehan /* 950285236Swhu * Moved completion call back here so that all received 951285236Swhu * messages (not just data messages) will trigger a response 952285236Swhu * message back to the host. 953250199Sgrehan */ 954301918Ssephe hv_nv_on_receive_completion(chan, vm_xfer_page_pkt->d.transaction_id, 955285236Swhu status); 956250199Sgrehan} 957250199Sgrehan 958250199Sgrehan/* 959285236Swhu * Net VSC on receive completion 960285236Swhu * 961285236Swhu * Send a receive completion packet to RNDIS device (ie NetVsp) 962250199Sgrehan */ 963301918Ssephestatic void 964301918Ssephehv_nv_on_receive_completion(struct hv_vmbus_channel *chan, uint64_t tid, 965285236Swhu uint32_t status) 966250199Sgrehan{ 967250199Sgrehan nvsp_msg rx_comp_msg; 968250199Sgrehan int retries = 0; 969250199Sgrehan int ret = 0; 970250199Sgrehan 971250199Sgrehan rx_comp_msg.hdr.msg_type = nvsp_msg_1_type_send_rndis_pkt_complete; 972250199Sgrehan 973250199Sgrehan /* Pass in the status */ 974250199Sgrehan rx_comp_msg.msgs.vers_1_msgs.send_rndis_pkt_complete.status = 975285236Swhu status; 976250199Sgrehan 977250199Sgrehanretry_send_cmplt: 978250199Sgrehan /* Send the completion */ 979301918Ssephe ret = hv_vmbus_channel_send_packet(chan, &rx_comp_msg, 980250199Sgrehan sizeof(nvsp_msg), tid, HV_VMBUS_PACKET_TYPE_COMPLETION, 0); 981250199Sgrehan if (ret == 0) { 982250199Sgrehan /* success */ 983250199Sgrehan /* no-op */ 984250199Sgrehan } else if (ret == EAGAIN) { 985250199Sgrehan /* no more room... wait a bit and attempt to retry 3 times */ 986250199Sgrehan retries++; 987250199Sgrehan 988250199Sgrehan if (retries < 4) { 989250199Sgrehan DELAY(100); 990250199Sgrehan goto retry_send_cmplt; 991250199Sgrehan } 992250199Sgrehan } 993250199Sgrehan} 994250199Sgrehan 995250199Sgrehan/* 996301943Ssephe * Net VSC receiving vRSS send table from VSP 997301943Ssephe */ 998301943Ssephestatic void 999301943Ssephehv_nv_send_table(struct hv_device *device, hv_vm_packet_descriptor *pkt) 1000301943Ssephe{ 1001301943Ssephe netvsc_dev *net_dev; 1002301943Ssephe nvsp_msg *nvsp_msg_pkt; 1003301943Ssephe int i; 1004301943Ssephe uint32_t count, *table; 1005301943Ssephe 1006301943Ssephe net_dev = hv_nv_get_inbound_net_device(device); 1007301943Ssephe if (!net_dev) 1008301943Ssephe return; 1009301943Ssephe 1010301943Ssephe nvsp_msg_pkt = 1011301943Ssephe (nvsp_msg *)((unsigned long)pkt + (pkt->data_offset8 << 3)); 1012301943Ssephe 1013301943Ssephe if (nvsp_msg_pkt->hdr.msg_type != 1014301943Ssephe nvsp_msg5_type_send_indirection_table) { 1015301943Ssephe printf("Netvsc: !Warning! receive msg type not " 1016301943Ssephe "send_indirection_table. type = %d\n", 1017301943Ssephe nvsp_msg_pkt->hdr.msg_type); 1018301943Ssephe return; 1019301943Ssephe } 1020301943Ssephe 1021301943Ssephe count = nvsp_msg_pkt->msgs.vers_5_msgs.send_table.count; 1022301943Ssephe if (count != VRSS_SEND_TABLE_SIZE) { 1023301943Ssephe printf("Netvsc: Received wrong send table size: %u\n", count); 1024301943Ssephe return; 1025301943Ssephe } 1026301943Ssephe 1027301943Ssephe table = (uint32_t *) 1028301943Ssephe ((unsigned long)&nvsp_msg_pkt->msgs.vers_5_msgs.send_table + 1029301943Ssephe nvsp_msg_pkt->msgs.vers_5_msgs.send_table.offset); 1030301943Ssephe 1031301943Ssephe for (i = 0; i < count; i++) 1032301943Ssephe net_dev->vrss_send_table[i] = table[i]; 1033301943Ssephe} 1034301943Ssephe 1035301943Ssephe/* 1036250199Sgrehan * Net VSC on channel callback 1037250199Sgrehan */ 1038250199Sgrehanstatic void 1039301912Ssephehv_nv_on_channel_callback(void *xchan) 1040250199Sgrehan{ 1041301912Ssephe struct hv_vmbus_channel *chan = xchan; 1042301912Ssephe struct hv_device *device = chan->device; 1043250199Sgrehan netvsc_dev *net_dev; 1044285236Swhu device_t dev = device->device; 1045250199Sgrehan uint32_t bytes_rxed; 1046250199Sgrehan uint64_t request_id; 1047285236Swhu hv_vm_packet_descriptor *desc; 1048250199Sgrehan uint8_t *buffer; 1049285236Swhu int bufferlen = NETVSC_PACKET_SIZE; 1050285236Swhu int ret = 0; 1051250199Sgrehan 1052285236Swhu net_dev = hv_nv_get_inbound_net_device(device); 1053285236Swhu if (net_dev == NULL) 1054250199Sgrehan return; 1055250199Sgrehan 1056301918Ssephe buffer = chan->hv_chan_rdbuf; 1057250199Sgrehan 1058250199Sgrehan do { 1059301912Ssephe ret = hv_vmbus_channel_recv_packet_raw(chan, 1060250199Sgrehan buffer, bufferlen, &bytes_rxed, &request_id); 1061250199Sgrehan if (ret == 0) { 1062250199Sgrehan if (bytes_rxed > 0) { 1063250199Sgrehan desc = (hv_vm_packet_descriptor *)buffer; 1064250199Sgrehan switch (desc->type) { 1065250199Sgrehan case HV_VMBUS_PACKET_TYPE_COMPLETION: 1066301943Ssephe hv_nv_on_send_completion(net_dev, device, 1067301943Ssephe chan, desc); 1068250199Sgrehan break; 1069250199Sgrehan case HV_VMBUS_PACKET_TYPE_DATA_USING_TRANSFER_PAGES: 1070301912Ssephe hv_nv_on_receive(net_dev, device, chan, desc); 1071250199Sgrehan break; 1072301943Ssephe case HV_VMBUS_PACKET_TYPE_DATA_IN_BAND: 1073301943Ssephe hv_nv_send_table(device, desc); 1074301943Ssephe break; 1075250199Sgrehan default: 1076285236Swhu device_printf(dev, 1077285236Swhu "hv_cb recv unknow type %d " 1078285236Swhu " packet\n", desc->type); 1079250199Sgrehan break; 1080250199Sgrehan } 1081250199Sgrehan } else { 1082250199Sgrehan break; 1083250199Sgrehan } 1084250199Sgrehan } else if (ret == ENOBUFS) { 1085250199Sgrehan /* Handle large packet */ 1086285236Swhu if (bufferlen > NETVSC_PACKET_SIZE) { 1087285236Swhu free(buffer, M_NETVSC); 1088285236Swhu buffer = NULL; 1089285236Swhu } 1090285236Swhu 1091285236Swhu /* alloc new buffer */ 1092285236Swhu buffer = malloc(bytes_rxed, M_NETVSC, M_NOWAIT); 1093250199Sgrehan if (buffer == NULL) { 1094285236Swhu device_printf(dev, 1095285236Swhu "hv_cb malloc buffer failed, len=%u\n", 1096285236Swhu bytes_rxed); 1097285236Swhu bufferlen = 0; 1098250199Sgrehan break; 1099250199Sgrehan } 1100250199Sgrehan bufferlen = bytes_rxed; 1101250199Sgrehan } 1102250199Sgrehan } while (1); 1103250199Sgrehan 1104285236Swhu if (bufferlen > NETVSC_PACKET_SIZE) 1105285236Swhu free(buffer, M_NETVSC); 1106295948Ssephe 1107301912Ssephe hv_rf_channel_rollup(chan); 1108250199Sgrehan} 1109