hv_netvsc_drv_freebsd.c revision 253869
1250199Sgrehan/*- 2250199Sgrehan * Copyright (c) 2010-2012 Citrix Inc. 3250199Sgrehan * Copyright (c) 2009-2012 Microsoft Corp. 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. 27250199Sgrehan */ 28250199Sgrehan 29250199Sgrehan/*- 30250199Sgrehan * Copyright (c) 2004-2006 Kip Macy 31250199Sgrehan * All rights reserved. 32250199Sgrehan * 33250199Sgrehan * Redistribution and use in source and binary forms, with or without 34250199Sgrehan * modification, are permitted provided that the following conditions 35250199Sgrehan * are met: 36250199Sgrehan * 1. Redistributions of source code must retain the above copyright 37250199Sgrehan * notice, this list of conditions and the following disclaimer. 38250199Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 39250199Sgrehan * notice, this list of conditions and the following disclaimer in the 40250199Sgrehan * documentation and/or other materials provided with the distribution. 41250199Sgrehan * 42250199Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 43250199Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 44250199Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 45250199Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 46250199Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 47250199Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 48250199Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49250199Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 50250199Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 51250199Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52250199Sgrehan * SUCH DAMAGE. 53250199Sgrehan */ 54250199Sgrehan 55250199Sgrehan#include <sys/param.h> 56250199Sgrehan#include <sys/systm.h> 57250199Sgrehan#include <sys/sockio.h> 58250199Sgrehan#include <sys/mbuf.h> 59250199Sgrehan#include <sys/malloc.h> 60250199Sgrehan#include <sys/module.h> 61250199Sgrehan#include <sys/kernel.h> 62250199Sgrehan#include <sys/socket.h> 63250199Sgrehan#include <sys/queue.h> 64250199Sgrehan#include <sys/lock.h> 65250199Sgrehan#include <sys/sx.h> 66250199Sgrehan 67250199Sgrehan#include <net/if.h> 68250199Sgrehan#include <net/if_arp.h> 69250199Sgrehan#include <net/ethernet.h> 70250199Sgrehan#include <net/if_dl.h> 71250199Sgrehan#include <net/if_media.h> 72250199Sgrehan 73250199Sgrehan#include <net/bpf.h> 74250199Sgrehan 75250199Sgrehan#include <net/if_types.h> 76250199Sgrehan#include <net/if_vlan_var.h> 77250199Sgrehan#include <net/if.h> 78250199Sgrehan 79250199Sgrehan#include <netinet/in_systm.h> 80250199Sgrehan#include <netinet/in.h> 81250199Sgrehan#include <netinet/ip.h> 82250199Sgrehan#include <netinet/if_ether.h> 83250199Sgrehan 84250199Sgrehan#include <vm/vm.h> 85250199Sgrehan#include <vm/vm_param.h> 86250199Sgrehan#include <vm/vm_kern.h> 87250199Sgrehan#include <vm/pmap.h> 88250199Sgrehan 89250199Sgrehan#include <machine/bus.h> 90250199Sgrehan#include <machine/resource.h> 91250199Sgrehan#include <machine/frame.h> 92250199Sgrehan#include <machine/vmparam.h> 93250199Sgrehan 94250199Sgrehan#include <sys/bus.h> 95250199Sgrehan#include <sys/rman.h> 96250199Sgrehan#include <sys/mutex.h> 97250199Sgrehan#include <sys/errno.h> 98250199Sgrehan#include <sys/types.h> 99250199Sgrehan#include <machine/atomic.h> 100250199Sgrehan 101250199Sgrehan#include <machine/intr_machdep.h> 102250199Sgrehan 103250199Sgrehan#include <dev/hyperv/include/hyperv.h> 104250199Sgrehan#include "hv_net_vsc.h" 105250199Sgrehan#include "hv_rndis.h" 106250199Sgrehan#include "hv_rndis_filter.h" 107250199Sgrehan 108250199Sgrehan 109250199Sgrehan/* Short for Hyper-V network interface */ 110250199Sgrehan#define NETVSC_DEVNAME "hn" 111250199Sgrehan 112250199Sgrehan/* 113250199Sgrehan * It looks like offset 0 of buf is reserved to hold the softc pointer. 114250199Sgrehan * The sc pointer evidently not needed, and is not presently populated. 115250199Sgrehan * The packet offset is where the netvsc_packet starts in the buffer. 116250199Sgrehan */ 117250199Sgrehan#define HV_NV_SC_PTR_OFFSET_IN_BUF 0 118250199Sgrehan#define HV_NV_PACKET_OFFSET_IN_BUF 16 119250199Sgrehan 120250199Sgrehan 121250199Sgrehan/* 122250199Sgrehan * Data types 123250199Sgrehan */ 124250199Sgrehan 125250199Sgrehanstruct hv_netvsc_driver_context { 126250199Sgrehan uint32_t drv_inited; 127250199Sgrehan}; 128250199Sgrehan 129250199Sgrehan/* 130250199Sgrehan * Be aware that this sleepable mutex will exhibit WITNESS errors when 131250199Sgrehan * certain TCP and ARP code paths are taken. This appears to be a 132250199Sgrehan * well-known condition, as all other drivers checked use a sleeping 133250199Sgrehan * mutex to protect their transmit paths. 134250199Sgrehan * Also Be aware that mutexes do not play well with semaphores, and there 135250199Sgrehan * is a conflicting semaphore in a certain channel code path. 136250199Sgrehan */ 137250199Sgrehan#define NV_LOCK_INIT(_sc, _name) \ 138250199Sgrehan mtx_init(&(_sc)->hn_lock, _name, MTX_NETWORK_LOCK, MTX_DEF) 139250199Sgrehan#define NV_LOCK(_sc) mtx_lock(&(_sc)->hn_lock) 140250199Sgrehan#define NV_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->hn_lock, MA_OWNED) 141250199Sgrehan#define NV_UNLOCK(_sc) mtx_unlock(&(_sc)->hn_lock) 142250199Sgrehan#define NV_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->hn_lock) 143250199Sgrehan 144250199Sgrehan 145250199Sgrehan/* 146250199Sgrehan * Globals 147250199Sgrehan */ 148250199Sgrehan 149250199Sgrehanint hv_promisc_mode = 0; /* normal mode by default */ 150250199Sgrehan 151250199Sgrehan/* The one and only one */ 152250199Sgrehanstatic struct hv_netvsc_driver_context g_netvsc_drv; 153250199Sgrehan 154250199Sgrehan 155250199Sgrehan/* 156250199Sgrehan * Forward declarations 157250199Sgrehan */ 158250199Sgrehanstatic void hn_stop(hn_softc_t *sc); 159250199Sgrehanstatic void hn_ifinit_locked(hn_softc_t *sc); 160250199Sgrehanstatic void hn_ifinit(void *xsc); 161250199Sgrehanstatic int hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 162250199Sgrehanstatic int hn_start_locked(struct ifnet *ifp); 163250199Sgrehanstatic void hn_start(struct ifnet *ifp); 164250199Sgrehan 165250199Sgrehan 166250199Sgrehan/* 167250199Sgrehan * NetVsc driver initialization 168250199Sgrehan * Note: Filter init is no longer required 169250199Sgrehan */ 170250199Sgrehanstatic int 171250199Sgrehannetvsc_drv_init(void) 172250199Sgrehan{ 173250199Sgrehan return (0); 174250199Sgrehan} 175250199Sgrehan 176250199Sgrehan/* 177250199Sgrehan * NetVsc global initialization entry point 178250199Sgrehan */ 179250199Sgrehanstatic void 180250199Sgrehannetvsc_init(void) 181250199Sgrehan{ 182250199Sgrehan printf("Netvsc initializing... "); 183250199Sgrehan 184250199Sgrehan /* 185250199Sgrehan * XXXKYS: cleanup initialization 186250199Sgrehan */ 187250199Sgrehan if (!cold && !g_netvsc_drv.drv_inited) { 188250199Sgrehan g_netvsc_drv.drv_inited = 1; 189250199Sgrehan netvsc_drv_init(); 190250199Sgrehan } else { 191250199Sgrehan printf("Already initialized!\n"); 192250199Sgrehan } 193250199Sgrehan} 194250199Sgrehan 195250199Sgrehan/* {F8615163-DF3E-46c5-913F-F2D2F965ED0E} */ 196250199Sgrehanstatic const hv_guid g_net_vsc_device_type = { 197250199Sgrehan .data = {0x63, 0x51, 0x61, 0xF8, 0x3E, 0xDF, 0xc5, 0x46, 198250199Sgrehan 0x91, 0x3F, 0xF2, 0xD2, 0xF9, 0x65, 0xED, 0x0E} 199250199Sgrehan}; 200250199Sgrehan 201250199Sgrehan/* 202250199Sgrehan * Standard probe entry point. 203250199Sgrehan * 204250199Sgrehan */ 205250199Sgrehanstatic int 206250199Sgrehannetvsc_probe(device_t dev) 207250199Sgrehan{ 208250199Sgrehan const char *p; 209250199Sgrehan 210250199Sgrehan p = vmbus_get_type(dev); 211250199Sgrehan if (!memcmp(p, &g_net_vsc_device_type.data, sizeof(hv_guid))) { 212250199Sgrehan device_set_desc(dev, "Synthetic Network Interface"); 213250199Sgrehan printf("Netvsc probe... DONE \n"); 214250199Sgrehan 215250199Sgrehan return (0); 216250199Sgrehan } 217250199Sgrehan 218250199Sgrehan return (ENXIO); 219250199Sgrehan} 220250199Sgrehan 221250199Sgrehan/* 222250199Sgrehan * Standard attach entry point. 223250199Sgrehan * 224250199Sgrehan * Called when the driver is loaded. It allocates needed resources, 225250199Sgrehan * and initializes the "hardware" and software. 226250199Sgrehan */ 227250199Sgrehanstatic int 228250199Sgrehannetvsc_attach(device_t dev) 229250199Sgrehan{ 230250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(dev); 231250199Sgrehan netvsc_device_info device_info; 232250199Sgrehan hn_softc_t *sc; 233250199Sgrehan int unit = device_get_unit(dev); 234250199Sgrehan struct ifnet *ifp; 235250199Sgrehan int ret; 236250199Sgrehan 237250199Sgrehan netvsc_init(); 238250199Sgrehan 239250199Sgrehan sc = device_get_softc(dev); 240250199Sgrehan if (sc == NULL) { 241250199Sgrehan return (ENOMEM); 242250199Sgrehan } 243250199Sgrehan 244250199Sgrehan bzero(sc, sizeof(hn_softc_t)); 245250199Sgrehan sc->hn_unit = unit; 246250199Sgrehan sc->hn_dev = dev; 247250199Sgrehan 248250199Sgrehan NV_LOCK_INIT(sc, "NetVSCLock"); 249250199Sgrehan 250250199Sgrehan sc->hn_dev_obj = device_ctx; 251250199Sgrehan 252250199Sgrehan ifp = sc->hn_ifp = sc->arpcom.ac_ifp = if_alloc(IFT_ETHER); 253250199Sgrehan ifp->if_softc = sc; 254250199Sgrehan 255250199Sgrehan if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 256250199Sgrehan ifp->if_dunit = unit; 257250199Sgrehan ifp->if_dname = NETVSC_DEVNAME; 258250199Sgrehan 259250199Sgrehan ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 260250199Sgrehan ifp->if_ioctl = hn_ioctl; 261250199Sgrehan ifp->if_start = hn_start; 262250199Sgrehan ifp->if_init = hn_ifinit; 263250199Sgrehan /* needed by hv_rf_on_device_add() code */ 264250199Sgrehan ifp->if_mtu = ETHERMTU; 265250199Sgrehan IFQ_SET_MAXLEN(&ifp->if_snd, 512); 266250199Sgrehan ifp->if_snd.ifq_drv_maxlen = 511; 267250199Sgrehan IFQ_SET_READY(&ifp->if_snd); 268250199Sgrehan 269250199Sgrehan /* 270250199Sgrehan * Tell upper layers that we support full VLAN capability. 271250199Sgrehan */ 272250199Sgrehan ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 273250199Sgrehan ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 274250199Sgrehan ifp->if_capenable |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 275250199Sgrehan 276250199Sgrehan ret = hv_rf_on_device_add(device_ctx, &device_info); 277250199Sgrehan if (ret != 0) { 278250199Sgrehan if_free(ifp); 279250199Sgrehan 280250199Sgrehan return (ret); 281250199Sgrehan } 282250199Sgrehan if (device_info.link_state == 0) { 283250199Sgrehan sc->hn_carrier = 1; 284250199Sgrehan } 285250199Sgrehan 286250199Sgrehan ether_ifattach(ifp, device_info.mac_addr); 287250199Sgrehan 288250199Sgrehan return (0); 289250199Sgrehan} 290250199Sgrehan 291250199Sgrehan/* 292250199Sgrehan * Standard detach entry point 293250199Sgrehan */ 294250199Sgrehanstatic int 295250199Sgrehannetvsc_detach(device_t dev) 296250199Sgrehan{ 297250199Sgrehan struct hv_device *hv_device = vmbus_get_devctx(dev); 298250199Sgrehan 299250199Sgrehan printf("netvsc_detach\n"); 300250199Sgrehan 301250199Sgrehan /* 302250199Sgrehan * XXXKYS: Need to clean up all our 303250199Sgrehan * driver state; this is the driver 304250199Sgrehan * unloading. 305250199Sgrehan */ 306250199Sgrehan 307250199Sgrehan /* 308250199Sgrehan * XXXKYS: Need to stop outgoing traffic and unregister 309250199Sgrehan * the netdevice. 310250199Sgrehan */ 311250199Sgrehan 312250199Sgrehan hv_rf_on_device_remove(hv_device, HV_RF_NV_DESTROY_CHANNEL); 313250199Sgrehan 314250199Sgrehan return (0); 315250199Sgrehan} 316250199Sgrehan 317250199Sgrehan/* 318250199Sgrehan * Standard shutdown entry point 319250199Sgrehan */ 320250199Sgrehanstatic int 321250199Sgrehannetvsc_shutdown(device_t dev) 322250199Sgrehan{ 323250199Sgrehan return (0); 324250199Sgrehan} 325250199Sgrehan 326250199Sgrehan/* 327250199Sgrehan * Send completion processing 328250199Sgrehan * 329250199Sgrehan * Note: It looks like offset 0 of buf is reserved to hold the softc 330250199Sgrehan * pointer. The sc pointer is not currently needed in this function, and 331250199Sgrehan * it is not presently populated by the TX function. 332250199Sgrehan */ 333250199Sgrehanvoid 334250199Sgrehannetvsc_xmit_completion(void *context) 335250199Sgrehan{ 336250199Sgrehan netvsc_packet *packet = (netvsc_packet *)context; 337250199Sgrehan struct mbuf *mb; 338250199Sgrehan uint8_t *buf; 339250199Sgrehan 340250199Sgrehan mb = (struct mbuf *)packet->compl.send.send_completion_tid; 341250199Sgrehan buf = ((uint8_t *)packet) - HV_NV_PACKET_OFFSET_IN_BUF; 342250199Sgrehan 343250199Sgrehan free(buf, M_DEVBUF); 344250199Sgrehan 345250199Sgrehan if (mb != NULL) { 346250199Sgrehan m_freem(mb); 347250199Sgrehan } 348250199Sgrehan} 349250199Sgrehan 350250199Sgrehan/* 351250199Sgrehan * Start a transmit of one or more packets 352250199Sgrehan */ 353250199Sgrehanstatic int 354250199Sgrehanhn_start_locked(struct ifnet *ifp) 355250199Sgrehan{ 356250199Sgrehan hn_softc_t *sc = ifp->if_softc; 357250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); 358250199Sgrehan uint8_t *buf; 359250199Sgrehan netvsc_packet *packet; 360250199Sgrehan struct mbuf *m_head, *m; 361250199Sgrehan struct mbuf *mc_head = NULL; 362250199Sgrehan int i; 363250199Sgrehan int num_frags; 364250199Sgrehan int len; 365250199Sgrehan int xlen; 366250199Sgrehan int rppi_size; 367250199Sgrehan int retries = 0; 368250199Sgrehan int ret = 0; 369250199Sgrehan 370250199Sgrehan while (!IFQ_DRV_IS_EMPTY(&sc->hn_ifp->if_snd)) { 371250199Sgrehan IFQ_DRV_DEQUEUE(&sc->hn_ifp->if_snd, m_head); 372250199Sgrehan if (m_head == NULL) { 373250199Sgrehan break; 374250199Sgrehan } 375250199Sgrehan 376250199Sgrehan len = 0; 377250199Sgrehan num_frags = 0; 378250199Sgrehan xlen = 0; 379250199Sgrehan 380250199Sgrehan /* Walk the mbuf list computing total length and num frags */ 381250199Sgrehan for (m = m_head; m != NULL; m = m->m_next) { 382250199Sgrehan if (m->m_len != 0) { 383250199Sgrehan num_frags++; 384250199Sgrehan len += m->m_len; 385250199Sgrehan } 386250199Sgrehan } 387250199Sgrehan 388250199Sgrehan /* 389250199Sgrehan * Reserve the number of pages requested. Currently, 390250199Sgrehan * one page is reserved for the message in the RNDIS 391250199Sgrehan * filter packet 392250199Sgrehan */ 393250199Sgrehan num_frags += HV_RF_NUM_TX_RESERVED_PAGE_BUFS; 394250199Sgrehan 395250199Sgrehan /* If exceeds # page_buffers in netvsc_packet */ 396250199Sgrehan if (num_frags > NETVSC_PACKET_MAXPAGE) { 397250199Sgrehan m_freem(m); 398250199Sgrehan 399250199Sgrehan return (EINVAL); 400250199Sgrehan } 401250199Sgrehan 402250199Sgrehan rppi_size = 0; 403250199Sgrehan if (m_head->m_flags & M_VLANTAG) { 404250199Sgrehan rppi_size = sizeof(rndis_per_packet_info) + 405250199Sgrehan sizeof(ndis_8021q_info); 406250199Sgrehan } 407250199Sgrehan 408250199Sgrehan /* 409250199Sgrehan * Allocate a buffer with space for a netvsc packet plus a 410250199Sgrehan * number of reserved areas. First comes a (currently 16 411250199Sgrehan * bytes, currently unused) reserved data area. Second is 412250199Sgrehan * the netvsc_packet, which includes (currently 4) page 413250199Sgrehan * buffers. Third (optional) is a rndis_per_packet_info 414250199Sgrehan * struct, but only if a VLAN tag should be inserted into the 415250199Sgrehan * Ethernet frame by the Hyper-V infrastructure. Fourth is 416250199Sgrehan * an area reserved for an rndis_filter_packet struct. 417250199Sgrehan * Changed malloc to M_NOWAIT to avoid sleep under spin lock. 418250199Sgrehan * No longer reserving extra space for page buffers, as they 419250199Sgrehan * are already part of the netvsc_packet. 420250199Sgrehan */ 421250199Sgrehan buf = malloc(HV_NV_PACKET_OFFSET_IN_BUF + 422250199Sgrehan sizeof(netvsc_packet) + rppi_size + 423250199Sgrehan sizeof(rndis_filter_packet), 424250199Sgrehan M_DEVBUF, M_ZERO | M_NOWAIT); 425250199Sgrehan if (buf == NULL) { 426250199Sgrehan m_freem(m); 427250199Sgrehan 428250199Sgrehan return (ENOMEM); 429250199Sgrehan } 430250199Sgrehan 431250199Sgrehan packet = (netvsc_packet *)(buf + HV_NV_PACKET_OFFSET_IN_BUF); 432250199Sgrehan *(vm_offset_t *)buf = HV_NV_SC_PTR_OFFSET_IN_BUF; 433250199Sgrehan 434250199Sgrehan /* 435250199Sgrehan * extension points to the area reserved for the 436250199Sgrehan * rndis_filter_packet, which is placed just after 437250199Sgrehan * the netvsc_packet (and rppi struct, if present; 438250199Sgrehan * length is updated later). 439250199Sgrehan */ 440250199Sgrehan packet->extension = packet + 1; 441250199Sgrehan 442250199Sgrehan /* Set up the rndis header */ 443250199Sgrehan packet->page_buf_count = num_frags; 444250199Sgrehan 445250199Sgrehan /* Initialize it from the mbuf */ 446250199Sgrehan packet->tot_data_buf_len = len; 447250199Sgrehan 448250199Sgrehan /* 449250199Sgrehan * If the Hyper-V infrastructure needs to embed a VLAN tag, 450250199Sgrehan * initialize netvsc_packet and rppi struct values as needed. 451250199Sgrehan */ 452250199Sgrehan if (rppi_size) { 453250199Sgrehan /* Lower layers need the VLAN TCI */ 454250199Sgrehan packet->vlan_tci = m_head->m_pkthdr.ether_vtag; 455250199Sgrehan } 456250199Sgrehan 457250199Sgrehan /* 458250199Sgrehan * Fill the page buffers with mbuf info starting at index 459250199Sgrehan * HV_RF_NUM_TX_RESERVED_PAGE_BUFS. 460250199Sgrehan */ 461250199Sgrehan i = HV_RF_NUM_TX_RESERVED_PAGE_BUFS; 462250199Sgrehan for (m = m_head; m != NULL; m = m->m_next) { 463250199Sgrehan if (m->m_len) { 464250199Sgrehan vm_offset_t paddr = 465250199Sgrehan vtophys(mtod(m, vm_offset_t)); 466250199Sgrehan packet->page_buffers[i].pfn = 467250199Sgrehan paddr >> PAGE_SHIFT; 468250199Sgrehan packet->page_buffers[i].offset = 469250199Sgrehan paddr & (PAGE_SIZE - 1); 470250199Sgrehan packet->page_buffers[i].length = m->m_len; 471250199Sgrehan i++; 472250199Sgrehan } 473250199Sgrehan } 474250199Sgrehan 475250199Sgrehan /* 476250199Sgrehan * If bpf, copy the mbuf chain. This is less expensive than 477250199Sgrehan * it appears; the mbuf clusters are not copied, only their 478250199Sgrehan * reference counts are incremented. 479250199Sgrehan * Needed to avoid a race condition where the completion 480250199Sgrehan * callback is invoked, freeing the mbuf chain, before the 481250199Sgrehan * bpf_mtap code has a chance to run. 482250199Sgrehan */ 483250199Sgrehan if (ifp->if_bpf) { 484250199Sgrehan mc_head = m_copypacket(m_head, M_DONTWAIT); 485250199Sgrehan } 486250199Sgrehanretry_send: 487250199Sgrehan /* Set the completion routine */ 488250199Sgrehan packet->compl.send.on_send_completion = netvsc_xmit_completion; 489250199Sgrehan packet->compl.send.send_completion_context = packet; 490250199Sgrehan packet->compl.send.send_completion_tid = (uint64_t)m_head; 491250199Sgrehan 492250199Sgrehan /* Removed critical_enter(), does not appear necessary */ 493250199Sgrehan ret = hv_rf_on_send(device_ctx, packet); 494250199Sgrehan 495250199Sgrehan if (ret == 0) { 496250199Sgrehan ifp->if_opackets++; 497250199Sgrehan /* if bpf && mc_head, call bpf_mtap code */ 498250199Sgrehan if (mc_head) { 499250199Sgrehan ETHER_BPF_MTAP(ifp, mc_head); 500250199Sgrehan } 501250199Sgrehan } else { 502250199Sgrehan retries++; 503250199Sgrehan if (retries < 4) { 504250199Sgrehan goto retry_send; 505250199Sgrehan } 506250199Sgrehan 507250199Sgrehan IF_PREPEND(&ifp->if_snd, m_head); 508250199Sgrehan ifp->if_drv_flags |= IFF_DRV_OACTIVE; 509250199Sgrehan 510250199Sgrehan /* 511250199Sgrehan * Null the mbuf pointer so the completion function 512250199Sgrehan * does not free the mbuf chain. We just pushed the 513250199Sgrehan * mbuf chain back on the if_snd queue. 514250199Sgrehan */ 515250199Sgrehan packet->compl.send.send_completion_tid = 0; 516250199Sgrehan 517250199Sgrehan /* 518250199Sgrehan * Release the resources since we will not get any 519250199Sgrehan * send completion 520250199Sgrehan */ 521250199Sgrehan netvsc_xmit_completion(packet); 522250199Sgrehan } 523250199Sgrehan 524250199Sgrehan /* if bpf && mc_head, free the mbuf chain copy */ 525250199Sgrehan if (mc_head) { 526250199Sgrehan m_freem(mc_head); 527250199Sgrehan } 528250199Sgrehan } 529250199Sgrehan 530250199Sgrehan return (ret); 531250199Sgrehan} 532250199Sgrehan 533250199Sgrehan/* 534250199Sgrehan * Link up/down notification 535250199Sgrehan */ 536250199Sgrehanvoid 537250199Sgrehannetvsc_linkstatus_callback(struct hv_device *device_obj, uint32_t status) 538250199Sgrehan{ 539250199Sgrehan hn_softc_t *sc = device_get_softc(device_obj->device); 540250199Sgrehan 541250199Sgrehan if (sc == NULL) { 542250199Sgrehan return; 543250199Sgrehan } 544250199Sgrehan 545250199Sgrehan if (status == 1) { 546250199Sgrehan sc->hn_carrier = 1; 547250199Sgrehan } else { 548250199Sgrehan sc->hn_carrier = 0; 549250199Sgrehan } 550250199Sgrehan} 551250199Sgrehan 552250199Sgrehan/* 553250199Sgrehan * Append the specified data to the indicated mbuf chain, 554250199Sgrehan * Extend the mbuf chain if the new data does not fit in 555250199Sgrehan * existing space. 556250199Sgrehan * 557250199Sgrehan * This is a minor rewrite of m_append() from sys/kern/uipc_mbuf.c. 558250199Sgrehan * There should be an equivalent in the kernel mbuf code, 559250199Sgrehan * but there does not appear to be one yet. 560250199Sgrehan * 561250199Sgrehan * Differs from m_append() in that additional mbufs are 562250199Sgrehan * allocated with cluster size MJUMPAGESIZE, and filled 563250199Sgrehan * accordingly. 564250199Sgrehan * 565250199Sgrehan * Return 1 if able to complete the job; otherwise 0. 566250199Sgrehan */ 567250199Sgrehanstatic int 568250199Sgrehanhv_m_append(struct mbuf *m0, int len, c_caddr_t cp) 569250199Sgrehan{ 570250199Sgrehan struct mbuf *m, *n; 571250199Sgrehan int remainder, space; 572250199Sgrehan 573250199Sgrehan for (m = m0; m->m_next != NULL; m = m->m_next) 574250199Sgrehan ; 575250199Sgrehan remainder = len; 576250199Sgrehan space = M_TRAILINGSPACE(m); 577250199Sgrehan if (space > 0) { 578250199Sgrehan /* 579250199Sgrehan * Copy into available space. 580250199Sgrehan */ 581250199Sgrehan if (space > remainder) 582250199Sgrehan space = remainder; 583250199Sgrehan bcopy(cp, mtod(m, caddr_t) + m->m_len, space); 584250199Sgrehan m->m_len += space; 585250199Sgrehan cp += space; 586250199Sgrehan remainder -= space; 587250199Sgrehan } 588250199Sgrehan while (remainder > 0) { 589250199Sgrehan /* 590250199Sgrehan * Allocate a new mbuf; could check space 591250199Sgrehan * and allocate a cluster instead. 592250199Sgrehan */ 593250199Sgrehan n = m_getjcl(M_DONTWAIT, m->m_type, 0, MJUMPAGESIZE); 594250199Sgrehan if (n == NULL) 595250199Sgrehan break; 596250199Sgrehan n->m_len = min(MJUMPAGESIZE, remainder); 597250199Sgrehan bcopy(cp, mtod(n, caddr_t), n->m_len); 598250199Sgrehan cp += n->m_len; 599250199Sgrehan remainder -= n->m_len; 600250199Sgrehan m->m_next = n; 601250199Sgrehan m = n; 602250199Sgrehan } 603250199Sgrehan if (m0->m_flags & M_PKTHDR) 604250199Sgrehan m0->m_pkthdr.len += len - remainder; 605250199Sgrehan 606250199Sgrehan return (remainder == 0); 607250199Sgrehan} 608250199Sgrehan 609250199Sgrehan 610250199Sgrehan/* 611250199Sgrehan * Called when we receive a data packet from the "wire" on the 612250199Sgrehan * specified device 613250199Sgrehan * 614250199Sgrehan * Note: This is no longer used as a callback 615250199Sgrehan */ 616250199Sgrehanint 617250199Sgrehannetvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet) 618250199Sgrehan{ 619250199Sgrehan hn_softc_t *sc = (hn_softc_t *)device_get_softc(device_ctx->device); 620250199Sgrehan struct mbuf *m_new; 621250199Sgrehan struct ifnet *ifp = sc->hn_ifp; 622250199Sgrehan int size; 623250199Sgrehan int i; 624250199Sgrehan 625250199Sgrehan if (sc == NULL) { 626250199Sgrehan return (0); /* TODO: KYS how can this be! */ 627250199Sgrehan } 628250199Sgrehan 629250199Sgrehan ifp = sc->arpcom.ac_ifp; 630250199Sgrehan 631250199Sgrehan if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 632250199Sgrehan return (0); 633250199Sgrehan } 634250199Sgrehan 635250199Sgrehan /* 636250199Sgrehan * Bail out if packet contains more data than configured MTU. 637250199Sgrehan */ 638250199Sgrehan if (packet->tot_data_buf_len > (ifp->if_mtu + ETHER_HDR_LEN)) { 639250199Sgrehan return (0); 640250199Sgrehan } 641250199Sgrehan 642250199Sgrehan /* 643250199Sgrehan * Get an mbuf with a cluster. For packets 2K or less, 644250199Sgrehan * get a standard 2K cluster. For anything larger, get a 645250199Sgrehan * 4K cluster. Any buffers larger than 4K can cause problems 646250199Sgrehan * if looped around to the Hyper-V TX channel, so avoid them. 647250199Sgrehan */ 648250199Sgrehan size = MCLBYTES; 649250199Sgrehan 650250199Sgrehan if (packet->tot_data_buf_len > MCLBYTES) { 651250199Sgrehan /* 4096 */ 652250199Sgrehan size = MJUMPAGESIZE; 653250199Sgrehan } 654250199Sgrehan 655250199Sgrehan m_new = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size); 656250199Sgrehan 657250199Sgrehan if (m_new == NULL) 658250199Sgrehan return (0); 659250199Sgrehan 660250199Sgrehan /* 661250199Sgrehan * Remove trailing junk from RX data buffer. 662250199Sgrehan * Fixme: This will not work for multiple Hyper-V RX buffers. 663250199Sgrehan * Fortunately, the channel gathers all RX data into one buffer. 664250199Sgrehan * 665250199Sgrehan * L2 frame length, with L2 header, not including CRC 666250199Sgrehan */ 667250199Sgrehan packet->page_buffers[0].length = packet->tot_data_buf_len; 668250199Sgrehan 669250199Sgrehan /* 670250199Sgrehan * Copy the received packet to one or more mbufs. 671250199Sgrehan * The copy is required since the memory pointed to by netvsc_packet 672250199Sgrehan * cannot be deallocated 673250199Sgrehan */ 674250199Sgrehan for (i=0; i < packet->page_buf_count; i++) { 675250199Sgrehan /* Shift virtual page number to form virtual page address */ 676250199Sgrehan uint8_t *vaddr = (uint8_t *) 677250199Sgrehan (packet->page_buffers[i].pfn << PAGE_SHIFT); 678250199Sgrehan 679250199Sgrehan hv_m_append(m_new, packet->page_buffers[i].length, 680250199Sgrehan vaddr + packet->page_buffers[i].offset); 681250199Sgrehan } 682250199Sgrehan 683250199Sgrehan m_new->m_pkthdr.rcvif = ifp; 684250199Sgrehan 685250199Sgrehan if ((packet->vlan_tci != 0) && 686250199Sgrehan (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0) { 687250199Sgrehan m_new->m_pkthdr.ether_vtag = packet->vlan_tci; 688250199Sgrehan m_new->m_flags |= M_VLANTAG; 689250199Sgrehan } 690250199Sgrehan 691250199Sgrehan /* 692250199Sgrehan * Note: Moved RX completion back to hv_nv_on_receive() so all 693250199Sgrehan * messages (not just data messages) will trigger a response. 694250199Sgrehan */ 695250199Sgrehan 696250199Sgrehan ifp->if_ipackets++; 697250199Sgrehan 698250199Sgrehan /* We're not holding the lock here, so don't release it */ 699250199Sgrehan (*ifp->if_input)(ifp, m_new); 700250199Sgrehan 701250199Sgrehan return (0); 702250199Sgrehan} 703250199Sgrehan 704250199Sgrehan/* 705250199Sgrehan * Standard ioctl entry point. Called when the user wants to configure 706250199Sgrehan * the interface. 707250199Sgrehan */ 708250199Sgrehanstatic int 709250199Sgrehanhn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 710250199Sgrehan{ 711250199Sgrehan hn_softc_t *sc = ifp->if_softc; 712250199Sgrehan struct ifreq *ifr = (struct ifreq *)data; 713250199Sgrehan netvsc_device_info device_info; 714250199Sgrehan struct hv_device *hn_dev; 715250199Sgrehan int mask, error = 0; 716250199Sgrehan 717250199Sgrehan switch(cmd) { 718250199Sgrehan 719250199Sgrehan case SIOCSIFADDR: 720250199Sgrehan case SIOCGIFADDR: 721250199Sgrehan error = ether_ioctl(ifp, cmd, data); 722250199Sgrehan break; 723250199Sgrehan case SIOCSIFMTU: 724250199Sgrehan hn_dev = vmbus_get_devctx(sc->hn_dev); 725250199Sgrehan 726250199Sgrehan NV_LOCK(sc); 727250199Sgrehan 728250199Sgrehan if (ifr->ifr_mtu > NETVSC_MAX_CONFIGURABLE_MTU) { 729250199Sgrehan error = EINVAL; 730250199Sgrehan NV_UNLOCK(sc); 731250199Sgrehan break; 732250199Sgrehan } 733250199Sgrehan /* Obtain and record requested MTU */ 734250199Sgrehan ifp->if_mtu = ifr->ifr_mtu; 735250199Sgrehan 736250199Sgrehan /* 737250199Sgrehan * We must remove and add back the device to cause the new 738250199Sgrehan * MTU to take effect. This includes tearing down, but not 739250199Sgrehan * deleting the channel, then bringing it back up. 740250199Sgrehan */ 741250199Sgrehan error = hv_rf_on_device_remove(hn_dev, HV_RF_NV_RETAIN_CHANNEL); 742250199Sgrehan if (error) { 743250199Sgrehan NV_UNLOCK(sc); 744250199Sgrehan break; 745250199Sgrehan } 746250199Sgrehan error = hv_rf_on_device_add(hn_dev, &device_info); 747250199Sgrehan if (error) { 748250199Sgrehan NV_UNLOCK(sc); 749250199Sgrehan break; 750250199Sgrehan } 751250199Sgrehan 752250199Sgrehan hn_ifinit_locked(sc); 753250199Sgrehan 754250199Sgrehan NV_UNLOCK(sc); 755250199Sgrehan break; 756250199Sgrehan case SIOCSIFFLAGS: 757250199Sgrehan NV_LOCK(sc); 758250199Sgrehan if (ifp->if_flags & IFF_UP) { 759250199Sgrehan /* 760250199Sgrehan * If only the state of the PROMISC flag changed, 761250199Sgrehan * then just use the 'set promisc mode' command 762250199Sgrehan * instead of reinitializing the entire NIC. Doing 763250199Sgrehan * a full re-init means reloading the firmware and 764250199Sgrehan * waiting for it to start up, which may take a 765250199Sgrehan * second or two. 766250199Sgrehan */ 767250199Sgrehan#ifdef notyet 768250199Sgrehan /* Fixme: Promiscuous mode? */ 769250199Sgrehan /* No promiscuous mode with Xen */ 770250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING && 771250199Sgrehan ifp->if_flags & IFF_PROMISC && 772250199Sgrehan !(sc->hn_if_flags & IFF_PROMISC)) { 773250199Sgrehan /* do something here for Hyper-V */ 774250199Sgrehan ; 775250199Sgrehan/* XN_SETBIT(sc, XN_RX_MODE, */ 776250199Sgrehan/* XN_RXMODE_RX_PROMISC); */ 777250199Sgrehan } else if (ifp->if_drv_flags & IFF_DRV_RUNNING && 778250199Sgrehan !(ifp->if_flags & IFF_PROMISC) && 779250199Sgrehan sc->hn_if_flags & IFF_PROMISC) { 780250199Sgrehan /* do something here for Hyper-V */ 781250199Sgrehan ; 782250199Sgrehan/* XN_CLRBIT(sc, XN_RX_MODE, */ 783250199Sgrehan/* XN_RXMODE_RX_PROMISC); */ 784250199Sgrehan } else 785250199Sgrehan#endif 786250199Sgrehan hn_ifinit_locked(sc); 787250199Sgrehan } else { 788250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 789250199Sgrehan hn_stop(sc); 790250199Sgrehan } 791250199Sgrehan } 792250199Sgrehan sc->hn_if_flags = ifp->if_flags; 793250199Sgrehan NV_UNLOCK(sc); 794250199Sgrehan error = 0; 795250199Sgrehan break; 796250199Sgrehan case SIOCSIFCAP: 797250199Sgrehan mask = ifr->ifr_reqcap ^ ifp->if_capenable; 798250199Sgrehan if (mask & IFCAP_HWCSUM) { 799250199Sgrehan if (IFCAP_HWCSUM & ifp->if_capenable) { 800250199Sgrehan ifp->if_capenable &= ~IFCAP_HWCSUM; 801250199Sgrehan } else { 802250199Sgrehan ifp->if_capenable |= IFCAP_HWCSUM; 803250199Sgrehan } 804250199Sgrehan } 805250199Sgrehan error = 0; 806250199Sgrehan break; 807250199Sgrehan case SIOCADDMULTI: 808250199Sgrehan case SIOCDELMULTI: 809250199Sgrehan#ifdef notyet 810250199Sgrehan /* Fixme: Multicast mode? */ 811250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 812250199Sgrehan NV_LOCK(sc); 813250199Sgrehan netvsc_setmulti(sc); 814250199Sgrehan NV_UNLOCK(sc); 815250199Sgrehan error = 0; 816250199Sgrehan } 817250199Sgrehan#endif 818250199Sgrehan /* FALLTHROUGH */ 819250199Sgrehan case SIOCSIFMEDIA: 820250199Sgrehan case SIOCGIFMEDIA: 821250199Sgrehan error = EINVAL; 822250199Sgrehan break; 823250199Sgrehan default: 824250199Sgrehan error = ether_ioctl(ifp, cmd, data); 825250199Sgrehan break; 826250199Sgrehan } 827250199Sgrehan 828250199Sgrehan return (error); 829250199Sgrehan} 830250199Sgrehan 831250199Sgrehan/* 832250199Sgrehan * 833250199Sgrehan */ 834250199Sgrehanstatic void 835250199Sgrehanhn_stop(hn_softc_t *sc) 836250199Sgrehan{ 837250199Sgrehan struct ifnet *ifp; 838250199Sgrehan int ret; 839250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); 840250199Sgrehan 841250199Sgrehan NV_LOCK_ASSERT(sc); 842250199Sgrehan ifp = sc->hn_ifp; 843250199Sgrehan 844250199Sgrehan printf(" Closing Device ...\n"); 845250199Sgrehan 846250199Sgrehan ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 847250199Sgrehan sc->hn_initdone = 0; 848250199Sgrehan 849250199Sgrehan ret = hv_rf_on_close(device_ctx); 850250199Sgrehan} 851250199Sgrehan 852250199Sgrehan/* 853250199Sgrehan * FreeBSD transmit entry point 854250199Sgrehan */ 855250199Sgrehanstatic void 856250199Sgrehanhn_start(struct ifnet *ifp) 857250199Sgrehan{ 858250199Sgrehan hn_softc_t *sc; 859250199Sgrehan 860250199Sgrehan sc = ifp->if_softc; 861250199Sgrehan NV_LOCK(sc); 862250199Sgrehan hn_start_locked(ifp); 863250199Sgrehan NV_UNLOCK(sc); 864250199Sgrehan} 865250199Sgrehan 866250199Sgrehan/* 867250199Sgrehan * 868250199Sgrehan */ 869250199Sgrehanstatic void 870250199Sgrehanhn_ifinit_locked(hn_softc_t *sc) 871250199Sgrehan{ 872250199Sgrehan struct ifnet *ifp; 873250199Sgrehan struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev); 874250199Sgrehan int ret; 875250199Sgrehan 876250199Sgrehan NV_LOCK_ASSERT(sc); 877250199Sgrehan 878250199Sgrehan ifp = sc->hn_ifp; 879250199Sgrehan 880250199Sgrehan if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 881250199Sgrehan return; 882250199Sgrehan } 883250199Sgrehan 884250199Sgrehan hv_promisc_mode = 1; 885250199Sgrehan 886250199Sgrehan ret = hv_rf_on_open(device_ctx); 887250199Sgrehan if (ret != 0) { 888250199Sgrehan return; 889250199Sgrehan } else { 890250199Sgrehan sc->hn_initdone = 1; 891250199Sgrehan } 892250199Sgrehan ifp->if_drv_flags |= IFF_DRV_RUNNING; 893250199Sgrehan ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 894250199Sgrehan} 895250199Sgrehan 896250199Sgrehan/* 897250199Sgrehan * 898250199Sgrehan */ 899250199Sgrehanstatic void 900250199Sgrehanhn_ifinit(void *xsc) 901250199Sgrehan{ 902250199Sgrehan hn_softc_t *sc = xsc; 903250199Sgrehan 904250199Sgrehan NV_LOCK(sc); 905250199Sgrehan hn_ifinit_locked(sc); 906250199Sgrehan NV_UNLOCK(sc); 907250199Sgrehan} 908250199Sgrehan 909250199Sgrehan#ifdef LATER 910250199Sgrehan/* 911250199Sgrehan * 912250199Sgrehan */ 913250199Sgrehanstatic void 914250199Sgrehanhn_watchdog(struct ifnet *ifp) 915250199Sgrehan{ 916250199Sgrehan hn_softc_t *sc; 917250199Sgrehan sc = ifp->if_softc; 918250199Sgrehan 919250199Sgrehan printf("hn%d: watchdog timeout -- resetting\n", sc->hn_unit); 920250199Sgrehan hn_ifinit(sc); /*???*/ 921250199Sgrehan ifp->if_oerrors++; 922250199Sgrehan} 923250199Sgrehan#endif 924250199Sgrehan 925250199Sgrehanstatic device_method_t netvsc_methods[] = { 926250199Sgrehan /* Device interface */ 927250199Sgrehan DEVMETHOD(device_probe, netvsc_probe), 928250199Sgrehan DEVMETHOD(device_attach, netvsc_attach), 929250199Sgrehan DEVMETHOD(device_detach, netvsc_detach), 930250199Sgrehan DEVMETHOD(device_shutdown, netvsc_shutdown), 931250199Sgrehan 932250199Sgrehan { 0, 0 } 933250199Sgrehan}; 934250199Sgrehan 935250199Sgrehanstatic driver_t netvsc_driver = { 936250199Sgrehan NETVSC_DEVNAME, 937250199Sgrehan netvsc_methods, 938250199Sgrehan sizeof(hn_softc_t) 939250199Sgrehan}; 940250199Sgrehan 941250199Sgrehanstatic devclass_t netvsc_devclass; 942250199Sgrehan 943250199SgrehanDRIVER_MODULE(hn, vmbus, netvsc_driver, netvsc_devclass, 0, 0); 944250199SgrehanMODULE_VERSION(hn, 1); 945250199SgrehanMODULE_DEPEND(hn, vmbus, 1, 1, 1); 946253869SgrehanSYSINIT(netvsc_initx, SI_SUB_KTHREAD_IDLE, SI_ORDER_MIDDLE + 1, netvsc_init, 947250199Sgrehan NULL); 948250199Sgrehan 949