1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev 22843e1988Sjohnlev /* 23fd0939efSDavid Edmondson * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24843e1988Sjohnlev * Use is subject to license terms. 25843e1988Sjohnlev */ 26843e1988Sjohnlev 27843e1988Sjohnlev /* 28843e1988Sjohnlev * 29843e1988Sjohnlev * Copyright (c) 2004 Christian Limpach. 30843e1988Sjohnlev * All rights reserved. 31843e1988Sjohnlev * 32843e1988Sjohnlev * Redistribution and use in source and binary forms, with or without 33843e1988Sjohnlev * modification, are permitted provided that the following conditions 34843e1988Sjohnlev * are met: 35843e1988Sjohnlev * 1. Redistributions of source code must retain the above copyright 36843e1988Sjohnlev * notice, this list of conditions and the following disclaimer. 37843e1988Sjohnlev * 2. Redistributions in binary form must reproduce the above copyright 38843e1988Sjohnlev * notice, this list of conditions and the following disclaimer in the 39843e1988Sjohnlev * documentation and/or other materials provided with the distribution. 40843e1988Sjohnlev * 3. This section intentionally left blank. 41843e1988Sjohnlev * 4. The name of the author may not be used to endorse or promote products 42843e1988Sjohnlev * derived from this software without specific prior written permission. 43843e1988Sjohnlev * 44843e1988Sjohnlev * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45843e1988Sjohnlev * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46843e1988Sjohnlev * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47843e1988Sjohnlev * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48843e1988Sjohnlev * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49843e1988Sjohnlev * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50843e1988Sjohnlev * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51843e1988Sjohnlev * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52843e1988Sjohnlev * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53843e1988Sjohnlev * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54843e1988Sjohnlev */ 55843e1988Sjohnlev /* 56843e1988Sjohnlev * Section 3 of the above license was updated in response to bug 6379571. 57843e1988Sjohnlev */ 58843e1988Sjohnlev 59843e1988Sjohnlev /* 6056567907SDavid Edmondson * xnf.c - GLDv3 network driver for domU. 6156567907SDavid Edmondson */ 6256567907SDavid Edmondson 6356567907SDavid Edmondson /* 6456567907SDavid Edmondson * This driver uses four per-instance locks: 6556567907SDavid Edmondson * 6656567907SDavid Edmondson * xnf_gref_lock: 6756567907SDavid Edmondson * 6856567907SDavid Edmondson * Protects access to the grant reference list stored in 6956567907SDavid Edmondson * xnf_gref_head. Grant references should be acquired and released 7056567907SDavid Edmondson * using gref_get() and gref_put() respectively. 7156567907SDavid Edmondson * 7256567907SDavid Edmondson * xnf_schedlock: 7356567907SDavid Edmondson * 7456567907SDavid Edmondson * Protects: 7556567907SDavid Edmondson * xnf_need_sched - used to record that a previous transmit attempt 7656567907SDavid Edmondson * failed (and consequently it will be necessary to call 7756567907SDavid Edmondson * mac_tx_update() when transmit resources are available). 7856567907SDavid Edmondson * xnf_pending_multicast - the number of multicast requests that 7956567907SDavid Edmondson * have been submitted to the backend for which we have not 8056567907SDavid Edmondson * processed responses. 8156567907SDavid Edmondson * 8256567907SDavid Edmondson * xnf_txlock: 8356567907SDavid Edmondson * 8456567907SDavid Edmondson * Protects the transmit ring (xnf_tx_ring) and associated 8556567907SDavid Edmondson * structures (notably xnf_tx_pkt_id and xnf_tx_pkt_id_head). 8656567907SDavid Edmondson * 8756567907SDavid Edmondson * xnf_rxlock: 8856567907SDavid Edmondson * 8956567907SDavid Edmondson * Protects the receive ring (xnf_rx_ring) and associated 9056567907SDavid Edmondson * structures (notably xnf_rx_pkt_info). 9156567907SDavid Edmondson * 9256567907SDavid Edmondson * If driver-global state that affects both the transmit and receive 9356567907SDavid Edmondson * rings is manipulated, both xnf_txlock and xnf_rxlock should be 9456567907SDavid Edmondson * held, in that order. 9556567907SDavid Edmondson * 9656567907SDavid Edmondson * xnf_schedlock is acquired both whilst holding xnf_txlock and 9756567907SDavid Edmondson * without. It should always be acquired after xnf_txlock if both are 9856567907SDavid Edmondson * held. 9956567907SDavid Edmondson * 10056567907SDavid Edmondson * Notes: 10156567907SDavid Edmondson * - atomic_add_64() is used to manipulate counters where we require 10256567907SDavid Edmondson * accuracy. For counters intended only for observation by humans, 10356567907SDavid Edmondson * post increment/decrement are used instead. 104843e1988Sjohnlev */ 105843e1988Sjohnlev 106843e1988Sjohnlev #include <sys/types.h> 107843e1988Sjohnlev #include <sys/errno.h> 108843e1988Sjohnlev #include <sys/param.h> 109843e1988Sjohnlev #include <sys/sysmacros.h> 110843e1988Sjohnlev #include <sys/systm.h> 111843e1988Sjohnlev #include <sys/stream.h> 112843e1988Sjohnlev #include <sys/strsubr.h> 11356567907SDavid Edmondson #include <sys/strsun.h> 114843e1988Sjohnlev #include <sys/conf.h> 115843e1988Sjohnlev #include <sys/ddi.h> 116843e1988Sjohnlev #include <sys/devops.h> 117843e1988Sjohnlev #include <sys/sunddi.h> 118843e1988Sjohnlev #include <sys/sunndi.h> 119843e1988Sjohnlev #include <sys/dlpi.h> 120843e1988Sjohnlev #include <sys/ethernet.h> 121843e1988Sjohnlev #include <sys/strsun.h> 122843e1988Sjohnlev #include <sys/pattr.h> 123843e1988Sjohnlev #include <inet/ip.h> 124a859da42SDavid Edmondson #include <inet/ip_impl.h> 125a859da42SDavid Edmondson #include <sys/gld.h> 126843e1988Sjohnlev #include <sys/modctl.h> 127da14cebeSEric Cheng #include <sys/mac_provider.h> 128843e1988Sjohnlev #include <sys/mac_ether.h> 129843e1988Sjohnlev #include <sys/bootinfo.h> 130843e1988Sjohnlev #include <sys/mach_mmu.h> 131551bc2a6Smrj #ifdef XPV_HVM_DRIVER 132551bc2a6Smrj #include <sys/xpv_support.h> 133551bc2a6Smrj #include <sys/hypervisor.h> 134551bc2a6Smrj #else 135551bc2a6Smrj #include <sys/hypervisor.h> 136843e1988Sjohnlev #include <sys/evtchn_impl.h> 137843e1988Sjohnlev #include <sys/balloon_impl.h> 138551bc2a6Smrj #endif 139551bc2a6Smrj #include <xen/public/io/netif.h> 140551bc2a6Smrj #include <sys/gnttab.h> 141843e1988Sjohnlev #include <xen/sys/xendev.h> 142551bc2a6Smrj #include <sys/sdt.h> 14356567907SDavid Edmondson #include <sys/note.h> 14456567907SDavid Edmondson #include <sys/debug.h> 145551bc2a6Smrj 146551bc2a6Smrj #include <io/xnf.h> 147551bc2a6Smrj 148843e1988Sjohnlev #if defined(DEBUG) || defined(__lint) 149843e1988Sjohnlev #define XNF_DEBUG 15056567907SDavid Edmondson #endif 15156567907SDavid Edmondson 15256567907SDavid Edmondson #ifdef XNF_DEBUG 15356567907SDavid Edmondson int xnf_debug = 0; 15456567907SDavid Edmondson xnf_t *xnf_debug_instance = NULL; 155843e1988Sjohnlev #endif 156843e1988Sjohnlev 157843e1988Sjohnlev /* 158843e1988Sjohnlev * On a 32 bit PAE system physical and machine addresses are larger 159843e1988Sjohnlev * than 32 bits. ddi_btop() on such systems take an unsigned long 160843e1988Sjohnlev * argument, and so addresses above 4G are truncated before ddi_btop() 161843e1988Sjohnlev * gets to see them. To avoid this, code the shift operation here. 162843e1988Sjohnlev */ 163843e1988Sjohnlev #define xnf_btop(addr) ((addr) >> PAGESHIFT) 164843e1988Sjohnlev 165843e1988Sjohnlev unsigned int xnf_max_tx_frags = 1; 166843e1988Sjohnlev 16756567907SDavid Edmondson /* 16856567907SDavid Edmondson * Should we use the multicast control feature if the backend provides 16956567907SDavid Edmondson * it? 17056567907SDavid Edmondson */ 17156567907SDavid Edmondson boolean_t xnf_multicast_control = B_TRUE; 17256567907SDavid Edmondson 17356567907SDavid Edmondson /* 17456567907SDavid Edmondson * Received packets below this size are copied to a new streams buffer 17556567907SDavid Edmondson * rather than being desballoc'ed. 17656567907SDavid Edmondson * 17756567907SDavid Edmondson * This value is chosen to accommodate traffic where there are a large 17856567907SDavid Edmondson * number of small packets. For data showing a typical distribution, 17956567907SDavid Edmondson * see: 18056567907SDavid Edmondson * 18156567907SDavid Edmondson * Sinha07a: 18256567907SDavid Edmondson * Rishi Sinha, Christos Papadopoulos, and John 18356567907SDavid Edmondson * Heidemann. Internet Packet Size Distributions: Some 18456567907SDavid Edmondson * Observations. Technical Report ISI-TR-2007-643, 18556567907SDavid Edmondson * USC/Information Sciences Institute, May, 2007. Orignally 18656567907SDavid Edmondson * released October 2005 as web page 18756567907SDavid Edmondson * http://netweb.usc.edu/~sinha/pkt-sizes/. 18856567907SDavid Edmondson * <http://www.isi.edu/~johnh/PAPERS/Sinha07a.html>. 18956567907SDavid Edmondson */ 19056567907SDavid Edmondson size_t xnf_rx_copy_limit = 64; 19156567907SDavid Edmondson 19256567907SDavid Edmondson #define INVALID_GRANT_HANDLE ((grant_handle_t)-1) 19356567907SDavid Edmondson #define INVALID_GRANT_REF ((grant_ref_t)-1) 19456567907SDavid Edmondson #define INVALID_TX_ID ((uint16_t)-1) 19556567907SDavid Edmondson 19656567907SDavid Edmondson #define TX_ID_TO_TXID(p, id) (&((p)->xnf_tx_pkt_id[(id)])) 19756567907SDavid Edmondson #define TX_ID_VALID(i) (((i) != INVALID_TX_ID) && ((i) < NET_TX_RING_SIZE)) 19856567907SDavid Edmondson 199843e1988Sjohnlev /* Required system entry points */ 200843e1988Sjohnlev static int xnf_attach(dev_info_t *, ddi_attach_cmd_t); 201843e1988Sjohnlev static int xnf_detach(dev_info_t *, ddi_detach_cmd_t); 202843e1988Sjohnlev 203843e1988Sjohnlev /* Required driver entry points for Nemo */ 204843e1988Sjohnlev static int xnf_start(void *); 205843e1988Sjohnlev static void xnf_stop(void *); 206843e1988Sjohnlev static int xnf_set_mac_addr(void *, const uint8_t *); 207843e1988Sjohnlev static int xnf_set_multicast(void *, boolean_t, const uint8_t *); 208843e1988Sjohnlev static int xnf_set_promiscuous(void *, boolean_t); 209843e1988Sjohnlev static mblk_t *xnf_send(void *, mblk_t *); 210843e1988Sjohnlev static uint_t xnf_intr(caddr_t); 211843e1988Sjohnlev static int xnf_stat(void *, uint_t, uint64_t *); 212843e1988Sjohnlev static boolean_t xnf_getcapab(void *, mac_capab_t, void *); 213843e1988Sjohnlev 214843e1988Sjohnlev /* Driver private functions */ 215843e1988Sjohnlev static int xnf_alloc_dma_resources(xnf_t *); 216843e1988Sjohnlev static void xnf_release_dma_resources(xnf_t *); 217843e1988Sjohnlev static void xnf_release_mblks(xnf_t *); 21856567907SDavid Edmondson 21956567907SDavid Edmondson static int xnf_buf_constructor(void *, void *, int); 22056567907SDavid Edmondson static void xnf_buf_destructor(void *, void *); 22156567907SDavid Edmondson static xnf_buf_t *xnf_buf_get(xnf_t *, int, boolean_t); 22256567907SDavid Edmondson #pragma inline(xnf_buf_get) 22356567907SDavid Edmondson static void xnf_buf_put(xnf_t *, xnf_buf_t *, boolean_t); 22456567907SDavid Edmondson #pragma inline(xnf_buf_put) 22556567907SDavid Edmondson static void xnf_buf_refresh(xnf_buf_t *); 22656567907SDavid Edmondson #pragma inline(xnf_buf_refresh) 22756567907SDavid Edmondson static void xnf_buf_recycle(xnf_buf_t *); 22856567907SDavid Edmondson 22956567907SDavid Edmondson static int xnf_tx_buf_constructor(void *, void *, int); 23056567907SDavid Edmondson static void xnf_tx_buf_destructor(void *, void *); 23156567907SDavid Edmondson 23256567907SDavid Edmondson static grant_ref_t gref_get(xnf_t *); 23356567907SDavid Edmondson #pragma inline(gref_get) 23456567907SDavid Edmondson static void gref_put(xnf_t *, grant_ref_t); 23556567907SDavid Edmondson #pragma inline(gref_put) 23656567907SDavid Edmondson 23756567907SDavid Edmondson static xnf_txid_t *txid_get(xnf_t *); 23856567907SDavid Edmondson #pragma inline(txid_get) 23956567907SDavid Edmondson static void txid_put(xnf_t *, xnf_txid_t *); 24056567907SDavid Edmondson #pragma inline(txid_put) 24156567907SDavid Edmondson 242843e1988Sjohnlev void xnf_send_driver_status(int, int); 24356567907SDavid Edmondson static void xnf_rxbuf_hang(xnf_t *, xnf_buf_t *); 24456567907SDavid Edmondson static int xnf_tx_clean_ring(xnf_t *); 245843e1988Sjohnlev static void oe_state_change(dev_info_t *, ddi_eventcookie_t, 246843e1988Sjohnlev void *, void *); 24756567907SDavid Edmondson static boolean_t xnf_kstat_init(xnf_t *); 24856567907SDavid Edmondson static void xnf_rx_collect(xnf_t *); 249843e1988Sjohnlev 250843e1988Sjohnlev static mac_callbacks_t xnf_callbacks = { 25156567907SDavid Edmondson MC_GETCAPAB, 252843e1988Sjohnlev xnf_stat, 253843e1988Sjohnlev xnf_start, 254843e1988Sjohnlev xnf_stop, 255843e1988Sjohnlev xnf_set_promiscuous, 256843e1988Sjohnlev xnf_set_multicast, 257843e1988Sjohnlev xnf_set_mac_addr, 258843e1988Sjohnlev xnf_send, 25956567907SDavid Edmondson NULL, 2600dc2366fSVenugopal Iyer NULL, 261843e1988Sjohnlev xnf_getcapab 262843e1988Sjohnlev }; 263843e1988Sjohnlev 264843e1988Sjohnlev /* DMA attributes for network ring buffer */ 265843e1988Sjohnlev static ddi_dma_attr_t ringbuf_dma_attr = { 266843e1988Sjohnlev DMA_ATTR_V0, /* version of this structure */ 267843e1988Sjohnlev 0, /* lowest usable address */ 268843e1988Sjohnlev 0xffffffffffffffffULL, /* highest usable address */ 269843e1988Sjohnlev 0x7fffffff, /* maximum DMAable byte count */ 270843e1988Sjohnlev MMU_PAGESIZE, /* alignment in bytes */ 271843e1988Sjohnlev 0x7ff, /* bitmap of burst sizes */ 272843e1988Sjohnlev 1, /* minimum transfer */ 273843e1988Sjohnlev 0xffffffffU, /* maximum transfer */ 274843e1988Sjohnlev 0xffffffffffffffffULL, /* maximum segment length */ 275843e1988Sjohnlev 1, /* maximum number of segments */ 276843e1988Sjohnlev 1, /* granularity */ 277843e1988Sjohnlev 0, /* flags (reserved) */ 278843e1988Sjohnlev }; 279843e1988Sjohnlev 28056567907SDavid Edmondson /* DMA attributes for transmit and receive data */ 28156567907SDavid Edmondson static ddi_dma_attr_t buf_dma_attr = { 282843e1988Sjohnlev DMA_ATTR_V0, /* version of this structure */ 283843e1988Sjohnlev 0, /* lowest usable address */ 284843e1988Sjohnlev 0xffffffffffffffffULL, /* highest usable address */ 285843e1988Sjohnlev 0x7fffffff, /* maximum DMAable byte count */ 286843e1988Sjohnlev MMU_PAGESIZE, /* alignment in bytes */ 287843e1988Sjohnlev 0x7ff, /* bitmap of burst sizes */ 288843e1988Sjohnlev 1, /* minimum transfer */ 289843e1988Sjohnlev 0xffffffffU, /* maximum transfer */ 290843e1988Sjohnlev 0xffffffffffffffffULL, /* maximum segment length */ 291843e1988Sjohnlev 1, /* maximum number of segments */ 292843e1988Sjohnlev 1, /* granularity */ 293843e1988Sjohnlev 0, /* flags (reserved) */ 294843e1988Sjohnlev }; 295843e1988Sjohnlev 296843e1988Sjohnlev /* DMA access attributes for registers and descriptors */ 297843e1988Sjohnlev static ddi_device_acc_attr_t accattr = { 298843e1988Sjohnlev DDI_DEVICE_ATTR_V0, 299843e1988Sjohnlev DDI_STRUCTURE_LE_ACC, /* This is a little-endian device */ 300843e1988Sjohnlev DDI_STRICTORDER_ACC 301843e1988Sjohnlev }; 302843e1988Sjohnlev 303843e1988Sjohnlev /* DMA access attributes for data: NOT to be byte swapped. */ 304843e1988Sjohnlev static ddi_device_acc_attr_t data_accattr = { 305843e1988Sjohnlev DDI_DEVICE_ATTR_V0, 306843e1988Sjohnlev DDI_NEVERSWAP_ACC, 307843e1988Sjohnlev DDI_STRICTORDER_ACC 308843e1988Sjohnlev }; 309843e1988Sjohnlev 310843e1988Sjohnlev DDI_DEFINE_STREAM_OPS(xnf_dev_ops, nulldev, nulldev, xnf_attach, xnf_detach, 31119397407SSherry Moore nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported); 312843e1988Sjohnlev 313843e1988Sjohnlev static struct modldrv xnf_modldrv = { 314a859da42SDavid Edmondson &mod_driverops, 315a859da42SDavid Edmondson "Virtual Ethernet driver", 316a859da42SDavid Edmondson &xnf_dev_ops 317843e1988Sjohnlev }; 318843e1988Sjohnlev 319843e1988Sjohnlev static struct modlinkage modlinkage = { 320843e1988Sjohnlev MODREV_1, &xnf_modldrv, NULL 321843e1988Sjohnlev }; 322843e1988Sjohnlev 323843e1988Sjohnlev int 324843e1988Sjohnlev _init(void) 325843e1988Sjohnlev { 326843e1988Sjohnlev int r; 327843e1988Sjohnlev 328843e1988Sjohnlev mac_init_ops(&xnf_dev_ops, "xnf"); 329843e1988Sjohnlev r = mod_install(&modlinkage); 330843e1988Sjohnlev if (r != DDI_SUCCESS) 331843e1988Sjohnlev mac_fini_ops(&xnf_dev_ops); 332843e1988Sjohnlev 333843e1988Sjohnlev return (r); 334843e1988Sjohnlev } 335843e1988Sjohnlev 336843e1988Sjohnlev int 337843e1988Sjohnlev _fini(void) 338843e1988Sjohnlev { 33956567907SDavid Edmondson return (EBUSY); /* XXPV should be removable */ 340843e1988Sjohnlev } 341843e1988Sjohnlev 342843e1988Sjohnlev int 343843e1988Sjohnlev _info(struct modinfo *modinfop) 344843e1988Sjohnlev { 345843e1988Sjohnlev return (mod_info(&modlinkage, modinfop)); 346843e1988Sjohnlev } 347843e1988Sjohnlev 34856567907SDavid Edmondson /* 34956567907SDavid Edmondson * Acquire a grant reference. 35056567907SDavid Edmondson */ 35156567907SDavid Edmondson static grant_ref_t 35256567907SDavid Edmondson gref_get(xnf_t *xnfp) 35356567907SDavid Edmondson { 35456567907SDavid Edmondson grant_ref_t gref; 35556567907SDavid Edmondson 35656567907SDavid Edmondson mutex_enter(&xnfp->xnf_gref_lock); 35756567907SDavid Edmondson 35856567907SDavid Edmondson do { 35956567907SDavid Edmondson gref = gnttab_claim_grant_reference(&xnfp->xnf_gref_head); 36056567907SDavid Edmondson 36156567907SDavid Edmondson } while ((gref == INVALID_GRANT_REF) && 36256567907SDavid Edmondson (gnttab_alloc_grant_references(16, &xnfp->xnf_gref_head) == 0)); 36356567907SDavid Edmondson 36456567907SDavid Edmondson mutex_exit(&xnfp->xnf_gref_lock); 36556567907SDavid Edmondson 36656567907SDavid Edmondson if (gref == INVALID_GRANT_REF) { 36756567907SDavid Edmondson xnfp->xnf_stat_gref_failure++; 36856567907SDavid Edmondson } else { 369*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&xnfp->xnf_stat_gref_outstanding); 37056567907SDavid Edmondson if (xnfp->xnf_stat_gref_outstanding > xnfp->xnf_stat_gref_peak) 37156567907SDavid Edmondson xnfp->xnf_stat_gref_peak = 37256567907SDavid Edmondson xnfp->xnf_stat_gref_outstanding; 37356567907SDavid Edmondson } 37456567907SDavid Edmondson 37556567907SDavid Edmondson return (gref); 37656567907SDavid Edmondson } 37756567907SDavid Edmondson 37856567907SDavid Edmondson /* 37956567907SDavid Edmondson * Release a grant reference. 38056567907SDavid Edmondson */ 38156567907SDavid Edmondson static void 38256567907SDavid Edmondson gref_put(xnf_t *xnfp, grant_ref_t gref) 38356567907SDavid Edmondson { 38456567907SDavid Edmondson ASSERT(gref != INVALID_GRANT_REF); 38556567907SDavid Edmondson 38656567907SDavid Edmondson mutex_enter(&xnfp->xnf_gref_lock); 38756567907SDavid Edmondson gnttab_release_grant_reference(&xnfp->xnf_gref_head, gref); 38856567907SDavid Edmondson mutex_exit(&xnfp->xnf_gref_lock); 38956567907SDavid Edmondson 390*1a5e258fSJosef 'Jeff' Sipek atomic_dec_64(&xnfp->xnf_stat_gref_outstanding); 39156567907SDavid Edmondson } 39256567907SDavid Edmondson 39356567907SDavid Edmondson /* 39456567907SDavid Edmondson * Acquire a transmit id. 39556567907SDavid Edmondson */ 39656567907SDavid Edmondson static xnf_txid_t * 39756567907SDavid Edmondson txid_get(xnf_t *xnfp) 39856567907SDavid Edmondson { 39956567907SDavid Edmondson xnf_txid_t *tidp; 40056567907SDavid Edmondson 40156567907SDavid Edmondson ASSERT(MUTEX_HELD(&xnfp->xnf_txlock)); 40256567907SDavid Edmondson 40356567907SDavid Edmondson if (xnfp->xnf_tx_pkt_id_head == INVALID_TX_ID) 40456567907SDavid Edmondson return (NULL); 40556567907SDavid Edmondson 40656567907SDavid Edmondson ASSERT(TX_ID_VALID(xnfp->xnf_tx_pkt_id_head)); 40756567907SDavid Edmondson 40856567907SDavid Edmondson tidp = TX_ID_TO_TXID(xnfp, xnfp->xnf_tx_pkt_id_head); 40956567907SDavid Edmondson xnfp->xnf_tx_pkt_id_head = tidp->next; 41056567907SDavid Edmondson tidp->next = INVALID_TX_ID; 41156567907SDavid Edmondson 41256567907SDavid Edmondson ASSERT(tidp->txbuf == NULL); 41356567907SDavid Edmondson 41456567907SDavid Edmondson return (tidp); 41556567907SDavid Edmondson } 41656567907SDavid Edmondson 41756567907SDavid Edmondson /* 41856567907SDavid Edmondson * Release a transmit id. 41956567907SDavid Edmondson */ 42056567907SDavid Edmondson static void 42156567907SDavid Edmondson txid_put(xnf_t *xnfp, xnf_txid_t *tidp) 42256567907SDavid Edmondson { 42356567907SDavid Edmondson ASSERT(MUTEX_HELD(&xnfp->xnf_txlock)); 42456567907SDavid Edmondson ASSERT(TX_ID_VALID(tidp->id)); 42556567907SDavid Edmondson ASSERT(tidp->next == INVALID_TX_ID); 42656567907SDavid Edmondson 42756567907SDavid Edmondson tidp->txbuf = NULL; 42856567907SDavid Edmondson tidp->next = xnfp->xnf_tx_pkt_id_head; 42956567907SDavid Edmondson xnfp->xnf_tx_pkt_id_head = tidp->id; 43056567907SDavid Edmondson } 43156567907SDavid Edmondson 43256567907SDavid Edmondson /* 43356567907SDavid Edmondson * Get `wanted' slots in the transmit ring, waiting for at least that 43456567907SDavid Edmondson * number if `wait' is B_TRUE. Force the ring to be cleaned by setting 43556567907SDavid Edmondson * `wanted' to zero. 43656567907SDavid Edmondson * 43756567907SDavid Edmondson * Return the number of slots available. 43856567907SDavid Edmondson */ 43956567907SDavid Edmondson static int 44056567907SDavid Edmondson tx_slots_get(xnf_t *xnfp, int wanted, boolean_t wait) 44156567907SDavid Edmondson { 44256567907SDavid Edmondson int slotsfree; 44356567907SDavid Edmondson boolean_t forced_clean = (wanted == 0); 44456567907SDavid Edmondson 44556567907SDavid Edmondson ASSERT(MUTEX_HELD(&xnfp->xnf_txlock)); 44656567907SDavid Edmondson 44756567907SDavid Edmondson /* LINTED: constant in conditional context */ 44856567907SDavid Edmondson while (B_TRUE) { 44956567907SDavid Edmondson slotsfree = RING_FREE_REQUESTS(&xnfp->xnf_tx_ring); 45056567907SDavid Edmondson 45156567907SDavid Edmondson if ((slotsfree < wanted) || forced_clean) 45256567907SDavid Edmondson slotsfree = xnf_tx_clean_ring(xnfp); 45356567907SDavid Edmondson 45456567907SDavid Edmondson /* 45556567907SDavid Edmondson * If there are more than we need free, tell other 45656567907SDavid Edmondson * people to come looking again. We hold txlock, so we 45756567907SDavid Edmondson * are able to take our slots before anyone else runs. 45856567907SDavid Edmondson */ 45956567907SDavid Edmondson if (slotsfree > wanted) 46056567907SDavid Edmondson cv_broadcast(&xnfp->xnf_cv_tx_slots); 46156567907SDavid Edmondson 46256567907SDavid Edmondson if (slotsfree >= wanted) 46356567907SDavid Edmondson break; 46456567907SDavid Edmondson 46556567907SDavid Edmondson if (!wait) 46656567907SDavid Edmondson break; 46756567907SDavid Edmondson 46856567907SDavid Edmondson cv_wait(&xnfp->xnf_cv_tx_slots, &xnfp->xnf_txlock); 46956567907SDavid Edmondson } 47056567907SDavid Edmondson 47156567907SDavid Edmondson ASSERT(slotsfree <= RING_SIZE(&(xnfp->xnf_tx_ring))); 47256567907SDavid Edmondson 47356567907SDavid Edmondson return (slotsfree); 47456567907SDavid Edmondson } 47556567907SDavid Edmondson 476843e1988Sjohnlev static int 477843e1988Sjohnlev xnf_setup_rings(xnf_t *xnfp) 478843e1988Sjohnlev { 479843e1988Sjohnlev domid_t oeid; 48056567907SDavid Edmondson struct xenbus_device *xsd; 48156567907SDavid Edmondson RING_IDX i; 48256567907SDavid Edmondson int err; 48356567907SDavid Edmondson xnf_txid_t *tidp; 48456567907SDavid Edmondson xnf_buf_t **bdescp; 485843e1988Sjohnlev 486551bc2a6Smrj oeid = xvdi_get_oeid(xnfp->xnf_devinfo); 487551bc2a6Smrj xsd = xvdi_get_xsd(xnfp->xnf_devinfo); 488843e1988Sjohnlev 48956567907SDavid Edmondson if (xnfp->xnf_tx_ring_ref != INVALID_GRANT_REF) 490551bc2a6Smrj gnttab_end_foreign_access(xnfp->xnf_tx_ring_ref, 0, 0); 491843e1988Sjohnlev 492843e1988Sjohnlev err = gnttab_grant_foreign_access(oeid, 493551bc2a6Smrj xnf_btop(pa_to_ma(xnfp->xnf_tx_ring_phys_addr)), 0); 494843e1988Sjohnlev if (err <= 0) { 495843e1988Sjohnlev err = -err; 496843e1988Sjohnlev xenbus_dev_error(xsd, err, "granting access to tx ring page"); 497843e1988Sjohnlev goto out; 498843e1988Sjohnlev } 499551bc2a6Smrj xnfp->xnf_tx_ring_ref = (grant_ref_t)err; 500843e1988Sjohnlev 50156567907SDavid Edmondson if (xnfp->xnf_rx_ring_ref != INVALID_GRANT_REF) 502551bc2a6Smrj gnttab_end_foreign_access(xnfp->xnf_rx_ring_ref, 0, 0); 503843e1988Sjohnlev 504843e1988Sjohnlev err = gnttab_grant_foreign_access(oeid, 505551bc2a6Smrj xnf_btop(pa_to_ma(xnfp->xnf_rx_ring_phys_addr)), 0); 506843e1988Sjohnlev if (err <= 0) { 507843e1988Sjohnlev err = -err; 508843e1988Sjohnlev xenbus_dev_error(xsd, err, "granting access to rx ring page"); 509843e1988Sjohnlev goto out; 510843e1988Sjohnlev } 511551bc2a6Smrj xnfp->xnf_rx_ring_ref = (grant_ref_t)err; 512843e1988Sjohnlev 513551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 514843e1988Sjohnlev 51556567907SDavid Edmondson /* 51656567907SDavid Edmondson * Setup/cleanup the TX ring. Note that this can lose packets 51756567907SDavid Edmondson * after a resume, but we expect to stagger on. 51856567907SDavid Edmondson */ 51956567907SDavid Edmondson xnfp->xnf_tx_pkt_id_head = INVALID_TX_ID; /* I.e. emtpy list. */ 52056567907SDavid Edmondson for (i = 0, tidp = &xnfp->xnf_tx_pkt_id[0]; 52156567907SDavid Edmondson i < NET_TX_RING_SIZE; 52256567907SDavid Edmondson i++, tidp++) { 52356567907SDavid Edmondson xnf_txbuf_t *txp; 524843e1988Sjohnlev 52556567907SDavid Edmondson tidp->id = i; 526843e1988Sjohnlev 52756567907SDavid Edmondson txp = tidp->txbuf; 52856567907SDavid Edmondson if (txp == NULL) { 52956567907SDavid Edmondson tidp->next = INVALID_TX_ID; /* Appease txid_put(). */ 53056567907SDavid Edmondson txid_put(xnfp, tidp); 531843e1988Sjohnlev continue; 532843e1988Sjohnlev } 533843e1988Sjohnlev 53456567907SDavid Edmondson ASSERT(txp->tx_txreq.gref != INVALID_GRANT_REF); 53556567907SDavid Edmondson ASSERT(txp->tx_mp != NULL); 536843e1988Sjohnlev 53756567907SDavid Edmondson switch (txp->tx_type) { 53856567907SDavid Edmondson case TX_DATA: 53956567907SDavid Edmondson VERIFY(gnttab_query_foreign_access(txp->tx_txreq.gref) 54056567907SDavid Edmondson == 0); 541843e1988Sjohnlev 54256567907SDavid Edmondson if (txp->tx_bdesc == NULL) { 54356567907SDavid Edmondson (void) gnttab_end_foreign_access_ref( 54456567907SDavid Edmondson txp->tx_txreq.gref, 1); 54556567907SDavid Edmondson gref_put(xnfp, txp->tx_txreq.gref); 54656567907SDavid Edmondson (void) ddi_dma_unbind_handle( 54756567907SDavid Edmondson txp->tx_dma_handle); 54856567907SDavid Edmondson } else { 54956567907SDavid Edmondson xnf_buf_put(xnfp, txp->tx_bdesc, B_TRUE); 550843e1988Sjohnlev } 551843e1988Sjohnlev 55256567907SDavid Edmondson freemsg(txp->tx_mp); 55356567907SDavid Edmondson txid_put(xnfp, tidp); 55456567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 555843e1988Sjohnlev 55656567907SDavid Edmondson break; 55756567907SDavid Edmondson 55856567907SDavid Edmondson case TX_MCAST_REQ: 55956567907SDavid Edmondson txp->tx_type = TX_MCAST_RSP; 56056567907SDavid Edmondson txp->tx_status = NETIF_RSP_DROPPED; 56156567907SDavid Edmondson cv_broadcast(&xnfp->xnf_cv_multicast); 56256567907SDavid Edmondson 56356567907SDavid Edmondson /* 56456567907SDavid Edmondson * The request consumed two slots in the ring, 56556567907SDavid Edmondson * yet only a single xnf_txid_t is used. Step 56656567907SDavid Edmondson * over the empty slot. 56756567907SDavid Edmondson */ 56856567907SDavid Edmondson i++; 56956567907SDavid Edmondson ASSERT(i < NET_TX_RING_SIZE); 57056567907SDavid Edmondson 57156567907SDavid Edmondson break; 57256567907SDavid Edmondson 57356567907SDavid Edmondson case TX_MCAST_RSP: 57456567907SDavid Edmondson break; 57556567907SDavid Edmondson } 57656567907SDavid Edmondson } 577a859da42SDavid Edmondson 578a859da42SDavid Edmondson /* LINTED: constant in conditional context */ 579a859da42SDavid Edmondson SHARED_RING_INIT(xnfp->xnf_tx_ring.sring); 58056567907SDavid Edmondson /* LINTED: constant in conditional context */ 58156567907SDavid Edmondson FRONT_RING_INIT(&xnfp->xnf_tx_ring, 58256567907SDavid Edmondson xnfp->xnf_tx_ring.sring, PAGESIZE); 583843e1988Sjohnlev 584551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 585843e1988Sjohnlev 58656567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 587551bc2a6Smrj 588843e1988Sjohnlev /* 58956567907SDavid Edmondson * Clean out any buffers currently posted to the receive ring 59056567907SDavid Edmondson * before we reset it. 591843e1988Sjohnlev */ 59256567907SDavid Edmondson for (i = 0, bdescp = &xnfp->xnf_rx_pkt_info[0]; 59356567907SDavid Edmondson i < NET_RX_RING_SIZE; 59456567907SDavid Edmondson i++, bdescp++) { 59556567907SDavid Edmondson if (*bdescp != NULL) { 59656567907SDavid Edmondson xnf_buf_put(xnfp, *bdescp, B_FALSE); 59756567907SDavid Edmondson *bdescp = NULL; 59856567907SDavid Edmondson } 59956567907SDavid Edmondson } 600a859da42SDavid Edmondson 601a859da42SDavid Edmondson /* LINTED: constant in conditional context */ 602a859da42SDavid Edmondson SHARED_RING_INIT(xnfp->xnf_rx_ring.sring); 60356567907SDavid Edmondson /* LINTED: constant in conditional context */ 60456567907SDavid Edmondson FRONT_RING_INIT(&xnfp->xnf_rx_ring, 60556567907SDavid Edmondson xnfp->xnf_rx_ring.sring, PAGESIZE); 606a859da42SDavid Edmondson 60756567907SDavid Edmondson /* 60856567907SDavid Edmondson * Fill the ring with buffers. 60956567907SDavid Edmondson */ 610843e1988Sjohnlev for (i = 0; i < NET_RX_RING_SIZE; i++) { 61156567907SDavid Edmondson xnf_buf_t *bdesc; 61256567907SDavid Edmondson 61356567907SDavid Edmondson bdesc = xnf_buf_get(xnfp, KM_SLEEP, B_FALSE); 61456567907SDavid Edmondson VERIFY(bdesc != NULL); 61556567907SDavid Edmondson xnf_rxbuf_hang(xnfp, bdesc); 616843e1988Sjohnlev } 61756567907SDavid Edmondson 618843e1988Sjohnlev /* LINTED: constant in conditional context */ 619551bc2a6Smrj RING_PUSH_REQUESTS(&xnfp->xnf_rx_ring); 620843e1988Sjohnlev 62156567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 622843e1988Sjohnlev 623843e1988Sjohnlev return (0); 624843e1988Sjohnlev 625843e1988Sjohnlev out: 62656567907SDavid Edmondson if (xnfp->xnf_tx_ring_ref != INVALID_GRANT_REF) 627551bc2a6Smrj gnttab_end_foreign_access(xnfp->xnf_tx_ring_ref, 0, 0); 62856567907SDavid Edmondson xnfp->xnf_tx_ring_ref = INVALID_GRANT_REF; 629843e1988Sjohnlev 63056567907SDavid Edmondson if (xnfp->xnf_rx_ring_ref != INVALID_GRANT_REF) 631551bc2a6Smrj gnttab_end_foreign_access(xnfp->xnf_rx_ring_ref, 0, 0); 63256567907SDavid Edmondson xnfp->xnf_rx_ring_ref = INVALID_GRANT_REF; 633843e1988Sjohnlev 634843e1988Sjohnlev return (err); 635843e1988Sjohnlev } 636843e1988Sjohnlev 637843e1988Sjohnlev /* 638843e1988Sjohnlev * Connect driver to back end, called to set up communication with 639843e1988Sjohnlev * back end driver both initially and on resume after restore/migrate. 640843e1988Sjohnlev */ 641843e1988Sjohnlev void 642843e1988Sjohnlev xnf_be_connect(xnf_t *xnfp) 643843e1988Sjohnlev { 644843e1988Sjohnlev const char *message; 645843e1988Sjohnlev xenbus_transaction_t xbt; 646843e1988Sjohnlev struct xenbus_device *xsd; 647843e1988Sjohnlev char *xsname; 648a390c5f4Scz147101 int err; 649843e1988Sjohnlev 650551bc2a6Smrj ASSERT(!xnfp->xnf_connected); 651843e1988Sjohnlev 652551bc2a6Smrj xsd = xvdi_get_xsd(xnfp->xnf_devinfo); 653551bc2a6Smrj xsname = xvdi_get_xsname(xnfp->xnf_devinfo); 654843e1988Sjohnlev 655843e1988Sjohnlev err = xnf_setup_rings(xnfp); 656843e1988Sjohnlev if (err != 0) { 657843e1988Sjohnlev cmn_err(CE_WARN, "failed to set up tx/rx rings"); 658843e1988Sjohnlev xenbus_dev_error(xsd, err, "setting up ring"); 659843e1988Sjohnlev return; 660843e1988Sjohnlev } 661843e1988Sjohnlev 662843e1988Sjohnlev again: 663843e1988Sjohnlev err = xenbus_transaction_start(&xbt); 664843e1988Sjohnlev if (err != 0) { 665843e1988Sjohnlev xenbus_dev_error(xsd, EIO, "starting transaction"); 666843e1988Sjohnlev return; 667843e1988Sjohnlev } 668843e1988Sjohnlev 669843e1988Sjohnlev err = xenbus_printf(xbt, xsname, "tx-ring-ref", "%u", 670551bc2a6Smrj xnfp->xnf_tx_ring_ref); 671843e1988Sjohnlev if (err != 0) { 672843e1988Sjohnlev message = "writing tx ring-ref"; 673843e1988Sjohnlev goto abort_transaction; 674843e1988Sjohnlev } 675843e1988Sjohnlev 676843e1988Sjohnlev err = xenbus_printf(xbt, xsname, "rx-ring-ref", "%u", 677551bc2a6Smrj xnfp->xnf_rx_ring_ref); 678843e1988Sjohnlev if (err != 0) { 679843e1988Sjohnlev message = "writing rx ring-ref"; 680843e1988Sjohnlev goto abort_transaction; 681843e1988Sjohnlev } 682843e1988Sjohnlev 683551bc2a6Smrj err = xenbus_printf(xbt, xsname, "event-channel", "%u", 684551bc2a6Smrj xnfp->xnf_evtchn); 685843e1988Sjohnlev if (err != 0) { 686843e1988Sjohnlev message = "writing event-channel"; 687843e1988Sjohnlev goto abort_transaction; 688843e1988Sjohnlev } 689843e1988Sjohnlev 690843e1988Sjohnlev err = xenbus_printf(xbt, xsname, "feature-rx-notify", "%d", 1); 691843e1988Sjohnlev if (err != 0) { 692843e1988Sjohnlev message = "writing feature-rx-notify"; 693843e1988Sjohnlev goto abort_transaction; 694843e1988Sjohnlev } 695843e1988Sjohnlev 69656567907SDavid Edmondson err = xenbus_printf(xbt, xsname, "request-rx-copy", "%d", 1); 697551bc2a6Smrj if (err != 0) { 698551bc2a6Smrj message = "writing request-rx-copy"; 699551bc2a6Smrj goto abort_transaction; 700551bc2a6Smrj } 701843e1988Sjohnlev 70256567907SDavid Edmondson if (xnfp->xnf_be_mcast_control) { 70356567907SDavid Edmondson err = xenbus_printf(xbt, xsname, "request-multicast-control", 70456567907SDavid Edmondson "%d", 1); 705843e1988Sjohnlev if (err != 0) { 70656567907SDavid Edmondson message = "writing request-multicast-control"; 70756567907SDavid Edmondson goto abort_transaction; 70856567907SDavid Edmondson } 70956567907SDavid Edmondson } 71056567907SDavid Edmondson 71156567907SDavid Edmondson err = xvdi_switch_state(xnfp->xnf_devinfo, xbt, XenbusStateConnected); 71256567907SDavid Edmondson if (err != 0) { 71356567907SDavid Edmondson message = "switching state to XenbusStateConnected"; 714843e1988Sjohnlev goto abort_transaction; 715843e1988Sjohnlev } 716843e1988Sjohnlev 717843e1988Sjohnlev err = xenbus_transaction_end(xbt, 0); 718843e1988Sjohnlev if (err != 0) { 719843e1988Sjohnlev if (err == EAGAIN) 720843e1988Sjohnlev goto again; 721843e1988Sjohnlev xenbus_dev_error(xsd, err, "completing transaction"); 722843e1988Sjohnlev } 723843e1988Sjohnlev 724843e1988Sjohnlev return; 725843e1988Sjohnlev 726843e1988Sjohnlev abort_transaction: 727843e1988Sjohnlev (void) xenbus_transaction_end(xbt, 1); 728843e1988Sjohnlev xenbus_dev_error(xsd, err, "%s", message); 729843e1988Sjohnlev } 730843e1988Sjohnlev 731843e1988Sjohnlev /* 73256567907SDavid Edmondson * Read configuration information from xenstore. 733a390c5f4Scz147101 */ 734a390c5f4Scz147101 void 735a390c5f4Scz147101 xnf_read_config(xnf_t *xnfp) 736a390c5f4Scz147101 { 73756567907SDavid Edmondson int err, be_cap; 738a390c5f4Scz147101 char mac[ETHERADDRL * 3]; 73956567907SDavid Edmondson char *oename = xvdi_get_oename(xnfp->xnf_devinfo); 740a390c5f4Scz147101 74156567907SDavid Edmondson err = xenbus_scanf(XBT_NULL, oename, "mac", 742a390c5f4Scz147101 "%s", (char *)&mac[0]); 743a390c5f4Scz147101 if (err != 0) { 744a390c5f4Scz147101 /* 745a390c5f4Scz147101 * bad: we're supposed to be set up with a proper mac 746a390c5f4Scz147101 * addr. at this point 747a390c5f4Scz147101 */ 748a390c5f4Scz147101 cmn_err(CE_WARN, "%s%d: no mac address", 749a390c5f4Scz147101 ddi_driver_name(xnfp->xnf_devinfo), 750a390c5f4Scz147101 ddi_get_instance(xnfp->xnf_devinfo)); 751a390c5f4Scz147101 return; 752a390c5f4Scz147101 } 753a390c5f4Scz147101 if (ether_aton(mac, xnfp->xnf_mac_addr) != ETHERADDRL) { 754a390c5f4Scz147101 err = ENOENT; 755a390c5f4Scz147101 xenbus_dev_error(xvdi_get_xsd(xnfp->xnf_devinfo), ENOENT, 756a390c5f4Scz147101 "parsing %s/mac", xvdi_get_xsname(xnfp->xnf_devinfo)); 757a390c5f4Scz147101 return; 758a390c5f4Scz147101 } 759a390c5f4Scz147101 76056567907SDavid Edmondson err = xenbus_scanf(XBT_NULL, oename, 76156567907SDavid Edmondson "feature-rx-copy", "%d", &be_cap); 762a390c5f4Scz147101 /* 763a390c5f4Scz147101 * If we fail to read the store we assume that the key is 764a390c5f4Scz147101 * absent, implying an older domain at the far end. Older 76556567907SDavid Edmondson * domains cannot do HV copy. 766a390c5f4Scz147101 */ 767a390c5f4Scz147101 if (err != 0) 76856567907SDavid Edmondson be_cap = 0; 76956567907SDavid Edmondson xnfp->xnf_be_rx_copy = (be_cap != 0); 77056567907SDavid Edmondson 77156567907SDavid Edmondson err = xenbus_scanf(XBT_NULL, oename, 77256567907SDavid Edmondson "feature-multicast-control", "%d", &be_cap); 773a390c5f4Scz147101 /* 77456567907SDavid Edmondson * If we fail to read the store we assume that the key is 77556567907SDavid Edmondson * absent, implying an older domain at the far end. Older 77656567907SDavid Edmondson * domains do not support multicast control. 777a390c5f4Scz147101 */ 77856567907SDavid Edmondson if (err != 0) 77956567907SDavid Edmondson be_cap = 0; 78056567907SDavid Edmondson xnfp->xnf_be_mcast_control = (be_cap != 0) && xnf_multicast_control; 781a390c5f4Scz147101 } 782a390c5f4Scz147101 783a390c5f4Scz147101 /* 784843e1988Sjohnlev * attach(9E) -- Attach a device to the system 785843e1988Sjohnlev */ 786843e1988Sjohnlev static int 787843e1988Sjohnlev xnf_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 788843e1988Sjohnlev { 789843e1988Sjohnlev mac_register_t *macp; 790843e1988Sjohnlev xnf_t *xnfp; 791843e1988Sjohnlev int err; 79256567907SDavid Edmondson char cachename[32]; 793843e1988Sjohnlev 794843e1988Sjohnlev #ifdef XNF_DEBUG 79556567907SDavid Edmondson if (xnf_debug & XNF_DEBUG_DDI) 796843e1988Sjohnlev printf("xnf%d: attach(0x%p)\n", ddi_get_instance(devinfo), 797843e1988Sjohnlev (void *)devinfo); 798843e1988Sjohnlev #endif 799843e1988Sjohnlev 800843e1988Sjohnlev switch (cmd) { 801843e1988Sjohnlev case DDI_RESUME: 802843e1988Sjohnlev xnfp = ddi_get_driver_private(devinfo); 80356567907SDavid Edmondson xnfp->xnf_gen++; 804843e1988Sjohnlev 805843e1988Sjohnlev (void) xvdi_resume(devinfo); 806843e1988Sjohnlev (void) xvdi_alloc_evtchn(devinfo); 807551bc2a6Smrj xnfp->xnf_evtchn = xvdi_get_evtchn(devinfo); 808551bc2a6Smrj #ifdef XPV_HVM_DRIVER 809551bc2a6Smrj ec_bind_evtchn_to_handler(xnfp->xnf_evtchn, IPL_VIF, xnf_intr, 810551bc2a6Smrj xnfp); 811551bc2a6Smrj #else 812843e1988Sjohnlev (void) ddi_add_intr(devinfo, 0, NULL, NULL, xnf_intr, 813843e1988Sjohnlev (caddr_t)xnfp); 814551bc2a6Smrj #endif 815843e1988Sjohnlev return (DDI_SUCCESS); 816843e1988Sjohnlev 817843e1988Sjohnlev case DDI_ATTACH: 818843e1988Sjohnlev break; 819843e1988Sjohnlev 820843e1988Sjohnlev default: 821843e1988Sjohnlev return (DDI_FAILURE); 822843e1988Sjohnlev } 823843e1988Sjohnlev 824843e1988Sjohnlev /* 825843e1988Sjohnlev * Allocate gld_mac_info_t and xnf_instance structures 826843e1988Sjohnlev */ 827843e1988Sjohnlev macp = mac_alloc(MAC_VERSION); 828843e1988Sjohnlev if (macp == NULL) 829843e1988Sjohnlev return (DDI_FAILURE); 830843e1988Sjohnlev xnfp = kmem_zalloc(sizeof (*xnfp), KM_SLEEP); 831843e1988Sjohnlev 832843e1988Sjohnlev macp->m_dip = devinfo; 833843e1988Sjohnlev macp->m_driver = xnfp; 834551bc2a6Smrj xnfp->xnf_devinfo = devinfo; 835843e1988Sjohnlev 836843e1988Sjohnlev macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 837551bc2a6Smrj macp->m_src_addr = xnfp->xnf_mac_addr; 838843e1988Sjohnlev macp->m_callbacks = &xnf_callbacks; 839843e1988Sjohnlev macp->m_min_sdu = 0; 840843e1988Sjohnlev macp->m_max_sdu = XNF_MAXPKT; 841843e1988Sjohnlev 842551bc2a6Smrj xnfp->xnf_running = B_FALSE; 843551bc2a6Smrj xnfp->xnf_connected = B_FALSE; 84456567907SDavid Edmondson xnfp->xnf_be_rx_copy = B_FALSE; 84556567907SDavid Edmondson xnfp->xnf_be_mcast_control = B_FALSE; 84664c5e63cSDavid Edmondson xnfp->xnf_need_sched = B_FALSE; 847551bc2a6Smrj 84856567907SDavid Edmondson xnfp->xnf_rx_head = NULL; 84956567907SDavid Edmondson xnfp->xnf_rx_tail = NULL; 85056567907SDavid Edmondson xnfp->xnf_rx_new_buffers_posted = B_FALSE; 85156567907SDavid Edmondson 852551bc2a6Smrj #ifdef XPV_HVM_DRIVER 8536eb35ee7Srab /* 8546eb35ee7Srab * Report our version to dom0. 8556eb35ee7Srab */ 856349b53ddSStuart Maybee if (xenbus_printf(XBT_NULL, "guest/xnf", "version", "%d", 8576eb35ee7Srab HVMPV_XNF_VERS)) 8586eb35ee7Srab cmn_err(CE_WARN, "xnf: couldn't write version\n"); 859551bc2a6Smrj #endif 860843e1988Sjohnlev 861843e1988Sjohnlev /* 862843e1988Sjohnlev * Get the iblock cookie with which to initialize the mutexes. 863843e1988Sjohnlev */ 864551bc2a6Smrj if (ddi_get_iblock_cookie(devinfo, 0, &xnfp->xnf_icookie) 865843e1988Sjohnlev != DDI_SUCCESS) 866843e1988Sjohnlev goto failure; 86756567907SDavid Edmondson 868551bc2a6Smrj mutex_init(&xnfp->xnf_txlock, 869551bc2a6Smrj NULL, MUTEX_DRIVER, xnfp->xnf_icookie); 87056567907SDavid Edmondson mutex_init(&xnfp->xnf_rxlock, 871551bc2a6Smrj NULL, MUTEX_DRIVER, xnfp->xnf_icookie); 87256567907SDavid Edmondson mutex_init(&xnfp->xnf_schedlock, 87356567907SDavid Edmondson NULL, MUTEX_DRIVER, xnfp->xnf_icookie); 87456567907SDavid Edmondson mutex_init(&xnfp->xnf_gref_lock, 87556567907SDavid Edmondson NULL, MUTEX_DRIVER, xnfp->xnf_icookie); 876843e1988Sjohnlev 87756567907SDavid Edmondson cv_init(&xnfp->xnf_cv_state, NULL, CV_DEFAULT, NULL); 87856567907SDavid Edmondson cv_init(&xnfp->xnf_cv_multicast, NULL, CV_DEFAULT, NULL); 87956567907SDavid Edmondson cv_init(&xnfp->xnf_cv_tx_slots, NULL, CV_DEFAULT, NULL); 88056567907SDavid Edmondson 88156567907SDavid Edmondson (void) sprintf(cachename, "xnf_buf_cache_%d", 88256567907SDavid Edmondson ddi_get_instance(devinfo)); 88356567907SDavid Edmondson xnfp->xnf_buf_cache = kmem_cache_create(cachename, 88456567907SDavid Edmondson sizeof (xnf_buf_t), 0, 88556567907SDavid Edmondson xnf_buf_constructor, xnf_buf_destructor, 88656567907SDavid Edmondson NULL, xnfp, NULL, 0); 88756567907SDavid Edmondson if (xnfp->xnf_buf_cache == NULL) 88856567907SDavid Edmondson goto failure_0; 88956567907SDavid Edmondson 89056567907SDavid Edmondson (void) sprintf(cachename, "xnf_tx_buf_cache_%d", 89156567907SDavid Edmondson ddi_get_instance(devinfo)); 89256567907SDavid Edmondson xnfp->xnf_tx_buf_cache = kmem_cache_create(cachename, 89356567907SDavid Edmondson sizeof (xnf_txbuf_t), 0, 89456567907SDavid Edmondson xnf_tx_buf_constructor, xnf_tx_buf_destructor, 89556567907SDavid Edmondson NULL, xnfp, NULL, 0); 89656567907SDavid Edmondson if (xnfp->xnf_tx_buf_cache == NULL) 897551bc2a6Smrj goto failure_1; 89856567907SDavid Edmondson 89956567907SDavid Edmondson xnfp->xnf_gref_head = INVALID_GRANT_REF; 90056567907SDavid Edmondson 901843e1988Sjohnlev if (xnf_alloc_dma_resources(xnfp) == DDI_FAILURE) { 902843e1988Sjohnlev cmn_err(CE_WARN, "xnf%d: failed to allocate and initialize " 903551bc2a6Smrj "driver data structures", 904551bc2a6Smrj ddi_get_instance(xnfp->xnf_devinfo)); 90556567907SDavid Edmondson goto failure_2; 906843e1988Sjohnlev } 907843e1988Sjohnlev 908551bc2a6Smrj xnfp->xnf_rx_ring.sring->rsp_event = 909551bc2a6Smrj xnfp->xnf_tx_ring.sring->rsp_event = 1; 910843e1988Sjohnlev 91156567907SDavid Edmondson xnfp->xnf_tx_ring_ref = INVALID_GRANT_REF; 91256567907SDavid Edmondson xnfp->xnf_rx_ring_ref = INVALID_GRANT_REF; 913843e1988Sjohnlev 914843e1988Sjohnlev /* set driver private pointer now */ 915843e1988Sjohnlev ddi_set_driver_private(devinfo, xnfp); 916843e1988Sjohnlev 917843e1988Sjohnlev if (!xnf_kstat_init(xnfp)) 91856567907SDavid Edmondson goto failure_3; 919843e1988Sjohnlev 920843e1988Sjohnlev /* 921843e1988Sjohnlev * Allocate an event channel, add the interrupt handler and 922843e1988Sjohnlev * bind it to the event channel. 923843e1988Sjohnlev */ 924843e1988Sjohnlev (void) xvdi_alloc_evtchn(devinfo); 925551bc2a6Smrj xnfp->xnf_evtchn = xvdi_get_evtchn(devinfo); 926551bc2a6Smrj #ifdef XPV_HVM_DRIVER 927551bc2a6Smrj ec_bind_evtchn_to_handler(xnfp->xnf_evtchn, IPL_VIF, xnf_intr, xnfp); 928551bc2a6Smrj #else 929843e1988Sjohnlev (void) ddi_add_intr(devinfo, 0, NULL, NULL, xnf_intr, (caddr_t)xnfp); 930551bc2a6Smrj #endif 931843e1988Sjohnlev 932551bc2a6Smrj err = mac_register(macp, &xnfp->xnf_mh); 933843e1988Sjohnlev mac_free(macp); 934843e1988Sjohnlev macp = NULL; 935843e1988Sjohnlev if (err != 0) 93656567907SDavid Edmondson goto failure_4; 93756567907SDavid Edmondson 93856567907SDavid Edmondson if (xvdi_add_event_handler(devinfo, XS_OE_STATE, oe_state_change, NULL) 93956567907SDavid Edmondson != DDI_SUCCESS) 94056567907SDavid Edmondson goto failure_5; 941843e1988Sjohnlev 942fb07ba1cSfvdl #ifdef XPV_HVM_DRIVER 943fb07ba1cSfvdl /* 944fb07ba1cSfvdl * In the HVM case, this driver essentially replaces a driver for 945fb07ba1cSfvdl * a 'real' PCI NIC. Without the "model" property set to 946fb07ba1cSfvdl * "Ethernet controller", like the PCI code does, netbooting does 947fb07ba1cSfvdl * not work correctly, as strplumb_get_netdev_path() will not find 948fb07ba1cSfvdl * this interface. 949fb07ba1cSfvdl */ 950fb07ba1cSfvdl (void) ndi_prop_update_string(DDI_DEV_T_NONE, devinfo, "model", 951fb07ba1cSfvdl "Ethernet controller"); 952fb07ba1cSfvdl #endif 953fb07ba1cSfvdl 95456567907SDavid Edmondson #ifdef XNF_DEBUG 95556567907SDavid Edmondson if (xnf_debug_instance == NULL) 95656567907SDavid Edmondson xnf_debug_instance = xnfp; 95756567907SDavid Edmondson #endif 958a390c5f4Scz147101 959843e1988Sjohnlev return (DDI_SUCCESS); 960843e1988Sjohnlev 96156567907SDavid Edmondson failure_5: 9621665cdc0SDavid Edmondson (void) mac_unregister(xnfp->xnf_mh); 96356567907SDavid Edmondson 96456567907SDavid Edmondson failure_4: 965551bc2a6Smrj #ifdef XPV_HVM_DRIVER 966551bc2a6Smrj ec_unbind_evtchn(xnfp->xnf_evtchn); 967ea8190a2Ssmaybe xvdi_free_evtchn(devinfo); 968551bc2a6Smrj #else 969551bc2a6Smrj ddi_remove_intr(devinfo, 0, xnfp->xnf_icookie); 970551bc2a6Smrj #endif 971551bc2a6Smrj xnfp->xnf_evtchn = INVALID_EVTCHN; 97256567907SDavid Edmondson kstat_delete(xnfp->xnf_kstat_aux); 97356567907SDavid Edmondson 97456567907SDavid Edmondson failure_3: 97556567907SDavid Edmondson xnf_release_dma_resources(xnfp); 976843e1988Sjohnlev 977a390c5f4Scz147101 failure_2: 97856567907SDavid Edmondson kmem_cache_destroy(xnfp->xnf_tx_buf_cache); 979a390c5f4Scz147101 980551bc2a6Smrj failure_1: 98156567907SDavid Edmondson kmem_cache_destroy(xnfp->xnf_buf_cache); 98256567907SDavid Edmondson 98356567907SDavid Edmondson failure_0: 98456567907SDavid Edmondson cv_destroy(&xnfp->xnf_cv_tx_slots); 98556567907SDavid Edmondson cv_destroy(&xnfp->xnf_cv_multicast); 98656567907SDavid Edmondson cv_destroy(&xnfp->xnf_cv_state); 98756567907SDavid Edmondson 98856567907SDavid Edmondson mutex_destroy(&xnfp->xnf_gref_lock); 98956567907SDavid Edmondson mutex_destroy(&xnfp->xnf_schedlock); 99056567907SDavid Edmondson mutex_destroy(&xnfp->xnf_rxlock); 991551bc2a6Smrj mutex_destroy(&xnfp->xnf_txlock); 992843e1988Sjohnlev 993843e1988Sjohnlev failure: 994843e1988Sjohnlev kmem_free(xnfp, sizeof (*xnfp)); 995843e1988Sjohnlev if (macp != NULL) 996843e1988Sjohnlev mac_free(macp); 997843e1988Sjohnlev 998843e1988Sjohnlev return (DDI_FAILURE); 999843e1988Sjohnlev } 1000843e1988Sjohnlev 1001843e1988Sjohnlev /* detach(9E) -- Detach a device from the system */ 1002843e1988Sjohnlev static int 1003843e1988Sjohnlev xnf_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 1004843e1988Sjohnlev { 1005843e1988Sjohnlev xnf_t *xnfp; /* Our private device info */ 1006843e1988Sjohnlev 1007843e1988Sjohnlev #ifdef XNF_DEBUG 100856567907SDavid Edmondson if (xnf_debug & XNF_DEBUG_DDI) 1009843e1988Sjohnlev printf("xnf_detach(0x%p)\n", (void *)devinfo); 1010843e1988Sjohnlev #endif 1011843e1988Sjohnlev 1012843e1988Sjohnlev xnfp = ddi_get_driver_private(devinfo); 1013843e1988Sjohnlev 1014843e1988Sjohnlev switch (cmd) { 1015843e1988Sjohnlev case DDI_SUSPEND: 1016551bc2a6Smrj #ifdef XPV_HVM_DRIVER 1017551bc2a6Smrj ec_unbind_evtchn(xnfp->xnf_evtchn); 1018ea8190a2Ssmaybe xvdi_free_evtchn(devinfo); 1019551bc2a6Smrj #else 1020551bc2a6Smrj ddi_remove_intr(devinfo, 0, xnfp->xnf_icookie); 1021551bc2a6Smrj #endif 1022843e1988Sjohnlev 1023843e1988Sjohnlev xvdi_suspend(devinfo); 1024843e1988Sjohnlev 102556567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 1026551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 1027843e1988Sjohnlev 1028551bc2a6Smrj xnfp->xnf_evtchn = INVALID_EVTCHN; 1029551bc2a6Smrj xnfp->xnf_connected = B_FALSE; 1030551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 103156567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 10324bae950fSMax zhen 10334bae950fSMax zhen /* claim link to be down after disconnect */ 10344bae950fSMax zhen mac_link_update(xnfp->xnf_mh, LINK_STATE_DOWN); 1035843e1988Sjohnlev return (DDI_SUCCESS); 1036843e1988Sjohnlev 1037843e1988Sjohnlev case DDI_DETACH: 1038843e1988Sjohnlev break; 1039843e1988Sjohnlev 1040843e1988Sjohnlev default: 1041843e1988Sjohnlev return (DDI_FAILURE); 1042843e1988Sjohnlev } 1043843e1988Sjohnlev 1044551bc2a6Smrj if (xnfp->xnf_connected) 1045843e1988Sjohnlev return (DDI_FAILURE); 1046843e1988Sjohnlev 104756567907SDavid Edmondson /* 104856567907SDavid Edmondson * Cannot detach if we have xnf_buf_t outstanding. 104956567907SDavid Edmondson */ 105056567907SDavid Edmondson if (xnfp->xnf_stat_buf_allocated > 0) 1051843e1988Sjohnlev return (DDI_FAILURE); 1052843e1988Sjohnlev 1053551bc2a6Smrj if (mac_unregister(xnfp->xnf_mh) != 0) 1054843e1988Sjohnlev return (DDI_FAILURE); 1055843e1988Sjohnlev 1056a390c5f4Scz147101 kstat_delete(xnfp->xnf_kstat_aux); 1057a390c5f4Scz147101 1058843e1988Sjohnlev /* Stop the receiver */ 1059843e1988Sjohnlev xnf_stop(xnfp); 1060843e1988Sjohnlev 1061843e1988Sjohnlev xvdi_remove_event_handler(devinfo, XS_OE_STATE); 1062843e1988Sjohnlev 1063843e1988Sjohnlev /* Remove the interrupt */ 1064551bc2a6Smrj #ifdef XPV_HVM_DRIVER 1065551bc2a6Smrj ec_unbind_evtchn(xnfp->xnf_evtchn); 1066ea8190a2Ssmaybe xvdi_free_evtchn(devinfo); 1067551bc2a6Smrj #else 1068551bc2a6Smrj ddi_remove_intr(devinfo, 0, xnfp->xnf_icookie); 1069551bc2a6Smrj #endif 1070843e1988Sjohnlev 1071843e1988Sjohnlev /* Release any pending xmit mblks */ 1072843e1988Sjohnlev xnf_release_mblks(xnfp); 1073843e1988Sjohnlev 1074843e1988Sjohnlev /* Release all DMA resources */ 1075843e1988Sjohnlev xnf_release_dma_resources(xnfp); 1076843e1988Sjohnlev 107756567907SDavid Edmondson cv_destroy(&xnfp->xnf_cv_tx_slots); 107856567907SDavid Edmondson cv_destroy(&xnfp->xnf_cv_multicast); 107956567907SDavid Edmondson cv_destroy(&xnfp->xnf_cv_state); 108056567907SDavid Edmondson 108156567907SDavid Edmondson kmem_cache_destroy(xnfp->xnf_tx_buf_cache); 108256567907SDavid Edmondson kmem_cache_destroy(xnfp->xnf_buf_cache); 108356567907SDavid Edmondson 108456567907SDavid Edmondson mutex_destroy(&xnfp->xnf_gref_lock); 108556567907SDavid Edmondson mutex_destroy(&xnfp->xnf_schedlock); 108656567907SDavid Edmondson mutex_destroy(&xnfp->xnf_rxlock); 1087551bc2a6Smrj mutex_destroy(&xnfp->xnf_txlock); 1088843e1988Sjohnlev 1089843e1988Sjohnlev kmem_free(xnfp, sizeof (*xnfp)); 1090843e1988Sjohnlev 1091843e1988Sjohnlev return (DDI_SUCCESS); 1092843e1988Sjohnlev } 1093843e1988Sjohnlev 1094843e1988Sjohnlev /* 1095843e1988Sjohnlev * xnf_set_mac_addr() -- set the physical network address on the board. 1096843e1988Sjohnlev */ 1097843e1988Sjohnlev static int 1098843e1988Sjohnlev xnf_set_mac_addr(void *arg, const uint8_t *macaddr) 1099843e1988Sjohnlev { 110056567907SDavid Edmondson _NOTE(ARGUNUSED(arg, macaddr)); 1101843e1988Sjohnlev 1102843e1988Sjohnlev /* 1103843e1988Sjohnlev * We can't set our macaddr. 1104843e1988Sjohnlev */ 1105843e1988Sjohnlev return (ENOTSUP); 1106843e1988Sjohnlev } 1107843e1988Sjohnlev 1108843e1988Sjohnlev /* 1109843e1988Sjohnlev * xnf_set_multicast() -- set (enable) or disable a multicast address. 1110843e1988Sjohnlev * 1111843e1988Sjohnlev * Program the hardware to enable/disable the multicast address 111256567907SDavid Edmondson * in "mca". Enable if "add" is true, disable if false. 1113843e1988Sjohnlev */ 1114843e1988Sjohnlev static int 1115843e1988Sjohnlev xnf_set_multicast(void *arg, boolean_t add, const uint8_t *mca) 1116843e1988Sjohnlev { 1117843e1988Sjohnlev xnf_t *xnfp = arg; 111856567907SDavid Edmondson xnf_txbuf_t *txp; 111956567907SDavid Edmondson int n_slots; 112056567907SDavid Edmondson RING_IDX slot; 112156567907SDavid Edmondson xnf_txid_t *tidp; 112256567907SDavid Edmondson netif_tx_request_t *txrp; 112356567907SDavid Edmondson struct netif_extra_info *erp; 112456567907SDavid Edmondson boolean_t notify, result; 1125843e1988Sjohnlev 1126843e1988Sjohnlev /* 112756567907SDavid Edmondson * If the backend does not support multicast control then we 112856567907SDavid Edmondson * must assume that the right packets will just arrive. 1129843e1988Sjohnlev */ 113056567907SDavid Edmondson if (!xnfp->xnf_be_mcast_control) 1131843e1988Sjohnlev return (0); 113256567907SDavid Edmondson 113356567907SDavid Edmondson txp = kmem_cache_alloc(xnfp->xnf_tx_buf_cache, KM_SLEEP); 113456567907SDavid Edmondson 113556567907SDavid Edmondson mutex_enter(&xnfp->xnf_txlock); 113656567907SDavid Edmondson 113756567907SDavid Edmondson /* 113856567907SDavid Edmondson * If we're not yet connected then claim success. This is 113956567907SDavid Edmondson * acceptable because we refresh the entire set of multicast 114056567907SDavid Edmondson * addresses when we get connected. 114156567907SDavid Edmondson * 114256567907SDavid Edmondson * We can't wait around here because the MAC layer expects 114356567907SDavid Edmondson * this to be a non-blocking operation - waiting ends up 114456567907SDavid Edmondson * causing a deadlock during resume. 114556567907SDavid Edmondson */ 114656567907SDavid Edmondson if (!xnfp->xnf_connected) { 114756567907SDavid Edmondson mutex_exit(&xnfp->xnf_txlock); 114856567907SDavid Edmondson return (0); 114956567907SDavid Edmondson } 115056567907SDavid Edmondson 115156567907SDavid Edmondson /* 115256567907SDavid Edmondson * 1. Acquire two slots in the ring. 115356567907SDavid Edmondson * 2. Fill in the slots. 115456567907SDavid Edmondson * 3. Request notification when the operation is done. 115556567907SDavid Edmondson * 4. Kick the peer. 115656567907SDavid Edmondson * 5. Wait for the response via xnf_tx_clean_ring(). 115756567907SDavid Edmondson */ 115856567907SDavid Edmondson 115956567907SDavid Edmondson n_slots = tx_slots_get(xnfp, 2, B_TRUE); 116056567907SDavid Edmondson ASSERT(n_slots >= 2); 116156567907SDavid Edmondson 116256567907SDavid Edmondson slot = xnfp->xnf_tx_ring.req_prod_pvt; 116356567907SDavid Edmondson tidp = txid_get(xnfp); 116456567907SDavid Edmondson VERIFY(tidp != NULL); 116556567907SDavid Edmondson 116656567907SDavid Edmondson txp->tx_type = TX_MCAST_REQ; 116756567907SDavid Edmondson txp->tx_slot = slot; 116856567907SDavid Edmondson 116956567907SDavid Edmondson txrp = RING_GET_REQUEST(&xnfp->xnf_tx_ring, slot); 117056567907SDavid Edmondson erp = (struct netif_extra_info *) 117156567907SDavid Edmondson RING_GET_REQUEST(&xnfp->xnf_tx_ring, slot + 1); 117256567907SDavid Edmondson 117356567907SDavid Edmondson txrp->gref = 0; 117456567907SDavid Edmondson txrp->size = 0; 117556567907SDavid Edmondson txrp->offset = 0; 117656567907SDavid Edmondson /* Set tx_txreq.id to appease xnf_tx_clean_ring(). */ 117756567907SDavid Edmondson txrp->id = txp->tx_txreq.id = tidp->id; 117856567907SDavid Edmondson txrp->flags = NETTXF_extra_info; 117956567907SDavid Edmondson 118056567907SDavid Edmondson erp->type = add ? XEN_NETIF_EXTRA_TYPE_MCAST_ADD : 118156567907SDavid Edmondson XEN_NETIF_EXTRA_TYPE_MCAST_DEL; 118256567907SDavid Edmondson bcopy((void *)mca, &erp->u.mcast.addr, ETHERADDRL); 118356567907SDavid Edmondson 118456567907SDavid Edmondson tidp->txbuf = txp; 118556567907SDavid Edmondson 118656567907SDavid Edmondson xnfp->xnf_tx_ring.req_prod_pvt = slot + 2; 118756567907SDavid Edmondson 118856567907SDavid Edmondson mutex_enter(&xnfp->xnf_schedlock); 118956567907SDavid Edmondson xnfp->xnf_pending_multicast++; 119056567907SDavid Edmondson mutex_exit(&xnfp->xnf_schedlock); 119156567907SDavid Edmondson 119256567907SDavid Edmondson /* LINTED: constant in conditional context */ 119356567907SDavid Edmondson RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xnfp->xnf_tx_ring, 119456567907SDavid Edmondson notify); 119556567907SDavid Edmondson if (notify) 119656567907SDavid Edmondson ec_notify_via_evtchn(xnfp->xnf_evtchn); 119756567907SDavid Edmondson 119856567907SDavid Edmondson while (txp->tx_type == TX_MCAST_REQ) 119956567907SDavid Edmondson cv_wait(&xnfp->xnf_cv_multicast, 120056567907SDavid Edmondson &xnfp->xnf_txlock); 120156567907SDavid Edmondson 120256567907SDavid Edmondson ASSERT(txp->tx_type == TX_MCAST_RSP); 120356567907SDavid Edmondson 120456567907SDavid Edmondson mutex_enter(&xnfp->xnf_schedlock); 120556567907SDavid Edmondson xnfp->xnf_pending_multicast--; 120656567907SDavid Edmondson mutex_exit(&xnfp->xnf_schedlock); 120756567907SDavid Edmondson 120856567907SDavid Edmondson result = (txp->tx_status == NETIF_RSP_OKAY); 120956567907SDavid Edmondson 121056567907SDavid Edmondson txid_put(xnfp, tidp); 121156567907SDavid Edmondson 121256567907SDavid Edmondson mutex_exit(&xnfp->xnf_txlock); 121356567907SDavid Edmondson 121456567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 121556567907SDavid Edmondson 121656567907SDavid Edmondson return (result ? 0 : 1); 1217843e1988Sjohnlev } 1218843e1988Sjohnlev 1219843e1988Sjohnlev /* 1220843e1988Sjohnlev * xnf_set_promiscuous() -- set or reset promiscuous mode on the board 1221843e1988Sjohnlev * 1222843e1988Sjohnlev * Program the hardware to enable/disable promiscuous mode. 1223843e1988Sjohnlev */ 1224843e1988Sjohnlev static int 1225843e1988Sjohnlev xnf_set_promiscuous(void *arg, boolean_t on) 1226843e1988Sjohnlev { 122756567907SDavid Edmondson _NOTE(ARGUNUSED(arg, on)); 1228843e1988Sjohnlev 1229843e1988Sjohnlev /* 1230843e1988Sjohnlev * We can't really do this, but we pretend that we can in 1231843e1988Sjohnlev * order that snoop will work. 1232843e1988Sjohnlev */ 1233843e1988Sjohnlev return (0); 1234843e1988Sjohnlev } 1235843e1988Sjohnlev 1236843e1988Sjohnlev /* 1237843e1988Sjohnlev * Clean buffers that we have responses for from the transmit ring. 1238843e1988Sjohnlev */ 1239843e1988Sjohnlev static int 124056567907SDavid Edmondson xnf_tx_clean_ring(xnf_t *xnfp) 1241843e1988Sjohnlev { 1242a390c5f4Scz147101 boolean_t work_to_do; 1243843e1988Sjohnlev 1244551bc2a6Smrj ASSERT(MUTEX_HELD(&xnfp->xnf_txlock)); 1245843e1988Sjohnlev 1246a390c5f4Scz147101 loop: 124766f1a35aSschuster while (RING_HAS_UNCONSUMED_RESPONSES(&xnfp->xnf_tx_ring)) { 124856567907SDavid Edmondson RING_IDX cons, prod, i; 124956567907SDavid Edmondson 125056567907SDavid Edmondson cons = xnfp->xnf_tx_ring.rsp_cons; 125156567907SDavid Edmondson prod = xnfp->xnf_tx_ring.sring->rsp_prod; 1252843e1988Sjohnlev membar_consumer(); 1253843e1988Sjohnlev /* 125456567907SDavid Edmondson * Clean tx requests from ring that we have responses 125556567907SDavid Edmondson * for. 1256843e1988Sjohnlev */ 125756567907SDavid Edmondson DTRACE_PROBE2(xnf_tx_clean_range, int, cons, int, prod); 125856567907SDavid Edmondson for (i = cons; i != prod; i++) { 125956567907SDavid Edmondson netif_tx_response_t *trp; 126056567907SDavid Edmondson xnf_txid_t *tidp; 126156567907SDavid Edmondson xnf_txbuf_t *txp; 126256567907SDavid Edmondson 126356567907SDavid Edmondson trp = RING_GET_RESPONSE(&xnfp->xnf_tx_ring, i); 126456567907SDavid Edmondson ASSERT(TX_ID_VALID(trp->id)); 126556567907SDavid Edmondson 126656567907SDavid Edmondson tidp = TX_ID_TO_TXID(xnfp, trp->id); 126756567907SDavid Edmondson ASSERT(tidp->id == trp->id); 126856567907SDavid Edmondson ASSERT(tidp->next == INVALID_TX_ID); 126956567907SDavid Edmondson 127056567907SDavid Edmondson txp = tidp->txbuf; 127156567907SDavid Edmondson ASSERT(txp != NULL); 127256567907SDavid Edmondson ASSERT(txp->tx_txreq.id == trp->id); 127356567907SDavid Edmondson 127456567907SDavid Edmondson switch (txp->tx_type) { 127556567907SDavid Edmondson case TX_DATA: 127656567907SDavid Edmondson if (gnttab_query_foreign_access( 127756567907SDavid Edmondson txp->tx_txreq.gref) != 0) 127856567907SDavid Edmondson cmn_err(CE_PANIC, 127956567907SDavid Edmondson "tx grant %d still in use by " 128056567907SDavid Edmondson "backend domain", 128156567907SDavid Edmondson txp->tx_txreq.gref); 128256567907SDavid Edmondson 128356567907SDavid Edmondson if (txp->tx_bdesc == NULL) { 128456567907SDavid Edmondson (void) gnttab_end_foreign_access_ref( 128556567907SDavid Edmondson txp->tx_txreq.gref, 1); 128656567907SDavid Edmondson gref_put(xnfp, txp->tx_txreq.gref); 128756567907SDavid Edmondson (void) ddi_dma_unbind_handle( 128856567907SDavid Edmondson txp->tx_dma_handle); 128956567907SDavid Edmondson } else { 129056567907SDavid Edmondson xnf_buf_put(xnfp, txp->tx_bdesc, 129156567907SDavid Edmondson B_TRUE); 1292843e1988Sjohnlev } 129356567907SDavid Edmondson 129456567907SDavid Edmondson freemsg(txp->tx_mp); 129556567907SDavid Edmondson txid_put(xnfp, tidp); 129656567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 129756567907SDavid Edmondson 129856567907SDavid Edmondson break; 129956567907SDavid Edmondson 130056567907SDavid Edmondson case TX_MCAST_REQ: 130156567907SDavid Edmondson txp->tx_type = TX_MCAST_RSP; 130256567907SDavid Edmondson txp->tx_status = trp->status; 130356567907SDavid Edmondson cv_broadcast(&xnfp->xnf_cv_multicast); 130456567907SDavid Edmondson 130556567907SDavid Edmondson break; 130656567907SDavid Edmondson 130756567907SDavid Edmondson case TX_MCAST_RSP: 130856567907SDavid Edmondson break; 130956567907SDavid Edmondson 131056567907SDavid Edmondson default: 131156567907SDavid Edmondson cmn_err(CE_PANIC, "xnf_tx_clean_ring: " 131256567907SDavid Edmondson "invalid xnf_txbuf_t type: %d", 131356567907SDavid Edmondson txp->tx_type); 131456567907SDavid Edmondson break; 131556567907SDavid Edmondson } 131656567907SDavid Edmondson } 131756567907SDavid Edmondson /* 131856567907SDavid Edmondson * Record the last response we dealt with so that we 131956567907SDavid Edmondson * know where to start next time around. 132056567907SDavid Edmondson */ 132156567907SDavid Edmondson xnfp->xnf_tx_ring.rsp_cons = prod; 1322843e1988Sjohnlev membar_enter(); 132366f1a35aSschuster } 132466f1a35aSschuster 1325a390c5f4Scz147101 /* LINTED: constant in conditional context */ 1326a390c5f4Scz147101 RING_FINAL_CHECK_FOR_RESPONSES(&xnfp->xnf_tx_ring, work_to_do); 1327a390c5f4Scz147101 if (work_to_do) 1328a390c5f4Scz147101 goto loop; 1329a390c5f4Scz147101 133066f1a35aSschuster return (RING_FREE_REQUESTS(&xnfp->xnf_tx_ring)); 1331843e1988Sjohnlev } 1332843e1988Sjohnlev 1333843e1988Sjohnlev /* 133456567907SDavid Edmondson * Allocate and fill in a look-aside buffer for the packet `mp'. Used 133556567907SDavid Edmondson * to ensure that the packet is physically contiguous and contained 133656567907SDavid Edmondson * within a single page. 1337843e1988Sjohnlev */ 133856567907SDavid Edmondson static xnf_buf_t * 133956567907SDavid Edmondson xnf_tx_pullup(xnf_t *xnfp, mblk_t *mp) 1340843e1988Sjohnlev { 134156567907SDavid Edmondson xnf_buf_t *bd; 1342843e1988Sjohnlev caddr_t bp; 1343843e1988Sjohnlev 134456567907SDavid Edmondson bd = xnf_buf_get(xnfp, KM_SLEEP, B_TRUE); 134556567907SDavid Edmondson if (bd == NULL) 134656567907SDavid Edmondson return (NULL); 134756567907SDavid Edmondson 134856567907SDavid Edmondson bp = bd->buf; 134956567907SDavid Edmondson while (mp != NULL) { 135056567907SDavid Edmondson size_t len = MBLKL(mp); 135156567907SDavid Edmondson 135256567907SDavid Edmondson bcopy(mp->b_rptr, bp, len); 1353843e1988Sjohnlev bp += len; 135456567907SDavid Edmondson 135556567907SDavid Edmondson mp = mp->b_cont; 1356843e1988Sjohnlev } 1357843e1988Sjohnlev 135856567907SDavid Edmondson ASSERT((bp - bd->buf) <= PAGESIZE); 135956567907SDavid Edmondson 136056567907SDavid Edmondson xnfp->xnf_stat_tx_pullup++; 136156567907SDavid Edmondson 136256567907SDavid Edmondson return (bd); 136356567907SDavid Edmondson } 136456567907SDavid Edmondson 136556567907SDavid Edmondson /* 136656567907SDavid Edmondson * Insert the pseudo-header checksum into the packet `buf'. 136756567907SDavid Edmondson */ 1368a859da42SDavid Edmondson void 1369a859da42SDavid Edmondson xnf_pseudo_cksum(caddr_t buf, int length) 1370a859da42SDavid Edmondson { 1371a859da42SDavid Edmondson struct ether_header *ehp; 1372a859da42SDavid Edmondson uint16_t sap, len, *stuff; 1373a859da42SDavid Edmondson uint32_t cksum; 1374a859da42SDavid Edmondson size_t offset; 1375a859da42SDavid Edmondson ipha_t *ipha; 1376a859da42SDavid Edmondson ipaddr_t src, dst; 1377a859da42SDavid Edmondson 1378a859da42SDavid Edmondson ASSERT(length >= sizeof (*ehp)); 1379a859da42SDavid Edmondson ehp = (struct ether_header *)buf; 1380a859da42SDavid Edmondson 1381a859da42SDavid Edmondson if (ntohs(ehp->ether_type) == VLAN_TPID) { 1382a859da42SDavid Edmondson struct ether_vlan_header *evhp; 1383a859da42SDavid Edmondson 1384a859da42SDavid Edmondson ASSERT(length >= sizeof (*evhp)); 1385a859da42SDavid Edmondson evhp = (struct ether_vlan_header *)buf; 1386a859da42SDavid Edmondson sap = ntohs(evhp->ether_type); 1387a859da42SDavid Edmondson offset = sizeof (*evhp); 1388a859da42SDavid Edmondson } else { 1389a859da42SDavid Edmondson sap = ntohs(ehp->ether_type); 1390a859da42SDavid Edmondson offset = sizeof (*ehp); 1391a859da42SDavid Edmondson } 1392a859da42SDavid Edmondson 1393a859da42SDavid Edmondson ASSERT(sap == ETHERTYPE_IP); 1394a859da42SDavid Edmondson 1395a859da42SDavid Edmondson /* Packet should have been pulled up by the caller. */ 1396a859da42SDavid Edmondson if ((offset + sizeof (ipha_t)) > length) { 1397a859da42SDavid Edmondson cmn_err(CE_WARN, "xnf_pseudo_cksum: no room for checksum"); 1398a859da42SDavid Edmondson return; 1399a859da42SDavid Edmondson } 1400a859da42SDavid Edmondson 1401a859da42SDavid Edmondson ipha = (ipha_t *)(buf + offset); 1402a859da42SDavid Edmondson 1403a859da42SDavid Edmondson ASSERT(IPH_HDR_LENGTH(ipha) == IP_SIMPLE_HDR_LENGTH); 1404a859da42SDavid Edmondson 1405a859da42SDavid Edmondson len = ntohs(ipha->ipha_length) - IP_SIMPLE_HDR_LENGTH; 1406a859da42SDavid Edmondson 1407a859da42SDavid Edmondson switch (ipha->ipha_protocol) { 1408a859da42SDavid Edmondson case IPPROTO_TCP: 1409a859da42SDavid Edmondson stuff = IPH_TCPH_CHECKSUMP(ipha, IP_SIMPLE_HDR_LENGTH); 1410a859da42SDavid Edmondson cksum = IP_TCP_CSUM_COMP; 1411a859da42SDavid Edmondson break; 1412a859da42SDavid Edmondson case IPPROTO_UDP: 1413a859da42SDavid Edmondson stuff = IPH_UDPH_CHECKSUMP(ipha, IP_SIMPLE_HDR_LENGTH); 1414a859da42SDavid Edmondson cksum = IP_UDP_CSUM_COMP; 1415a859da42SDavid Edmondson break; 1416a859da42SDavid Edmondson default: 1417a859da42SDavid Edmondson cmn_err(CE_WARN, "xnf_pseudo_cksum: unexpected protocol %d", 1418a859da42SDavid Edmondson ipha->ipha_protocol); 1419a859da42SDavid Edmondson return; 1420a859da42SDavid Edmondson } 1421a859da42SDavid Edmondson 1422a859da42SDavid Edmondson src = ipha->ipha_src; 1423a859da42SDavid Edmondson dst = ipha->ipha_dst; 1424a859da42SDavid Edmondson 1425a859da42SDavid Edmondson cksum += (dst >> 16) + (dst & 0xFFFF); 1426a859da42SDavid Edmondson cksum += (src >> 16) + (src & 0xFFFF); 1427a859da42SDavid Edmondson cksum += htons(len); 1428a859da42SDavid Edmondson 1429a859da42SDavid Edmondson cksum = (cksum >> 16) + (cksum & 0xFFFF); 1430a859da42SDavid Edmondson cksum = (cksum >> 16) + (cksum & 0xFFFF); 1431a859da42SDavid Edmondson 1432a859da42SDavid Edmondson ASSERT(cksum <= 0xFFFF); 1433a859da42SDavid Edmondson 1434a859da42SDavid Edmondson *stuff = (uint16_t)(cksum ? cksum : ~cksum); 1435a859da42SDavid Edmondson } 1436a859da42SDavid Edmondson 1437843e1988Sjohnlev /* 143856567907SDavid Edmondson * Push a list of prepared packets (`txp') into the transmit ring. 1439843e1988Sjohnlev */ 144056567907SDavid Edmondson static xnf_txbuf_t * 144156567907SDavid Edmondson tx_push_packets(xnf_t *xnfp, xnf_txbuf_t *txp) 1442843e1988Sjohnlev { 144356567907SDavid Edmondson int slots_free; 14443a79cf1eSschuster RING_IDX slot; 144556567907SDavid Edmondson boolean_t notify; 1446843e1988Sjohnlev 144756567907SDavid Edmondson mutex_enter(&xnfp->xnf_txlock); 1448843e1988Sjohnlev 144956567907SDavid Edmondson ASSERT(xnfp->xnf_running); 1450843e1988Sjohnlev 1451843e1988Sjohnlev /* 145256567907SDavid Edmondson * Wait until we are connected to the backend. 1453843e1988Sjohnlev */ 145456567907SDavid Edmondson while (!xnfp->xnf_connected) 145556567907SDavid Edmondson cv_wait(&xnfp->xnf_cv_state, &xnfp->xnf_txlock); 145656567907SDavid Edmondson 145756567907SDavid Edmondson slots_free = tx_slots_get(xnfp, 1, B_FALSE); 145856567907SDavid Edmondson DTRACE_PROBE1(xnf_send_slotsfree, int, slots_free); 1459843e1988Sjohnlev 146066f1a35aSschuster slot = xnfp->xnf_tx_ring.req_prod_pvt; 1461843e1988Sjohnlev 146256567907SDavid Edmondson while ((txp != NULL) && (slots_free > 0)) { 146356567907SDavid Edmondson xnf_txid_t *tidp; 146456567907SDavid Edmondson netif_tx_request_t *txrp; 146556567907SDavid Edmondson 146656567907SDavid Edmondson tidp = txid_get(xnfp); 146756567907SDavid Edmondson VERIFY(tidp != NULL); 146856567907SDavid Edmondson 146956567907SDavid Edmondson txrp = RING_GET_REQUEST(&xnfp->xnf_tx_ring, slot); 147056567907SDavid Edmondson 147156567907SDavid Edmondson txp->tx_slot = slot; 147256567907SDavid Edmondson txp->tx_txreq.id = tidp->id; 147356567907SDavid Edmondson *txrp = txp->tx_txreq; 147456567907SDavid Edmondson 147556567907SDavid Edmondson tidp->txbuf = txp; 147656567907SDavid Edmondson 147756567907SDavid Edmondson xnfp->xnf_stat_opackets++; 147856567907SDavid Edmondson xnfp->xnf_stat_obytes += txp->tx_txreq.size; 147956567907SDavid Edmondson 148056567907SDavid Edmondson txp = txp->tx_next; 148156567907SDavid Edmondson slots_free--; 148256567907SDavid Edmondson slot++; 148356567907SDavid Edmondson 148456567907SDavid Edmondson } 148556567907SDavid Edmondson 148656567907SDavid Edmondson xnfp->xnf_tx_ring.req_prod_pvt = slot; 148756567907SDavid Edmondson 148856567907SDavid Edmondson /* 148956567907SDavid Edmondson * Tell the peer that we sent something, if it cares. 149056567907SDavid Edmondson */ 149156567907SDavid Edmondson /* LINTED: constant in conditional context */ 149256567907SDavid Edmondson RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xnfp->xnf_tx_ring, 149356567907SDavid Edmondson notify); 149456567907SDavid Edmondson if (notify) 149556567907SDavid Edmondson ec_notify_via_evtchn(xnfp->xnf_evtchn); 149656567907SDavid Edmondson 149756567907SDavid Edmondson mutex_exit(&xnfp->xnf_txlock); 149856567907SDavid Edmondson 149956567907SDavid Edmondson return (txp); 1500843e1988Sjohnlev } 1501843e1988Sjohnlev 1502843e1988Sjohnlev /* 150356567907SDavid Edmondson * Send the chain of packets `mp'. Called by the MAC framework. 1504843e1988Sjohnlev */ 150556567907SDavid Edmondson static mblk_t * 150656567907SDavid Edmondson xnf_send(void *arg, mblk_t *mp) 150756567907SDavid Edmondson { 150856567907SDavid Edmondson xnf_t *xnfp = arg; 150956567907SDavid Edmondson domid_t oeid; 151056567907SDavid Edmondson xnf_txbuf_t *head, *tail; 151156567907SDavid Edmondson mblk_t *ml; 151256567907SDavid Edmondson int prepared; 151356567907SDavid Edmondson 151456567907SDavid Edmondson oeid = xvdi_get_oeid(xnfp->xnf_devinfo); 151556567907SDavid Edmondson 1516843e1988Sjohnlev /* 151756567907SDavid Edmondson * Prepare packets for transmission. 1518843e1988Sjohnlev */ 151956567907SDavid Edmondson head = tail = NULL; 152056567907SDavid Edmondson prepared = 0; 152156567907SDavid Edmondson while (mp != NULL) { 152256567907SDavid Edmondson xnf_txbuf_t *txp; 152356567907SDavid Edmondson int n_chunks, length; 152456567907SDavid Edmondson boolean_t page_oops; 152556567907SDavid Edmondson uint32_t pflags; 152656567907SDavid Edmondson 152756567907SDavid Edmondson for (ml = mp, n_chunks = length = 0, page_oops = B_FALSE; 152856567907SDavid Edmondson ml != NULL; 152956567907SDavid Edmondson ml = ml->b_cont, n_chunks++) { 153056567907SDavid Edmondson 153156567907SDavid Edmondson /* 153256567907SDavid Edmondson * Test if this buffer includes a page 153356567907SDavid Edmondson * boundary. The test assumes that the range 153456567907SDavid Edmondson * b_rptr...b_wptr can include only a single 153556567907SDavid Edmondson * boundary. 153656567907SDavid Edmondson */ 153756567907SDavid Edmondson if (xnf_btop((size_t)ml->b_rptr) != 153856567907SDavid Edmondson xnf_btop((size_t)ml->b_wptr)) { 1539551bc2a6Smrj xnfp->xnf_stat_tx_pagebndry++; 154056567907SDavid Edmondson page_oops = B_TRUE; 1541843e1988Sjohnlev } 1542843e1988Sjohnlev 154356567907SDavid Edmondson length += MBLKL(ml); 154456567907SDavid Edmondson } 154556567907SDavid Edmondson DTRACE_PROBE1(xnf_send_b_cont, int, n_chunks); 1546843e1988Sjohnlev 1547843e1988Sjohnlev /* 154856567907SDavid Edmondson * Make sure packet isn't too large. 1549843e1988Sjohnlev */ 155056567907SDavid Edmondson if (length > XNF_FRAMESIZE) { 155156567907SDavid Edmondson cmn_err(CE_WARN, 155256567907SDavid Edmondson "xnf%d: oversized packet (%d bytes) dropped", 155356567907SDavid Edmondson ddi_get_instance(xnfp->xnf_devinfo), length); 155456567907SDavid Edmondson freemsg(mp); 155556567907SDavid Edmondson continue; 155656567907SDavid Edmondson } 1557843e1988Sjohnlev 155856567907SDavid Edmondson txp = kmem_cache_alloc(xnfp->xnf_tx_buf_cache, KM_SLEEP); 155956567907SDavid Edmondson 156056567907SDavid Edmondson txp->tx_type = TX_DATA; 156156567907SDavid Edmondson 156256567907SDavid Edmondson if ((n_chunks > xnf_max_tx_frags) || page_oops) { 156356567907SDavid Edmondson /* 156456567907SDavid Edmondson * Loan a side buffer rather than the mblk 156556567907SDavid Edmondson * itself. 156656567907SDavid Edmondson */ 156756567907SDavid Edmondson txp->tx_bdesc = xnf_tx_pullup(xnfp, mp); 156856567907SDavid Edmondson if (txp->tx_bdesc == NULL) { 156956567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 157056567907SDavid Edmondson break; 157156567907SDavid Edmondson } 157256567907SDavid Edmondson 157356567907SDavid Edmondson txp->tx_bufp = txp->tx_bdesc->buf; 157456567907SDavid Edmondson txp->tx_mfn = txp->tx_bdesc->buf_mfn; 157556567907SDavid Edmondson txp->tx_txreq.gref = txp->tx_bdesc->grant_ref; 157656567907SDavid Edmondson 157756567907SDavid Edmondson } else { 157856567907SDavid Edmondson int rc; 157956567907SDavid Edmondson ddi_dma_cookie_t dma_cookie; 158056567907SDavid Edmondson uint_t ncookies; 158156567907SDavid Edmondson 158256567907SDavid Edmondson rc = ddi_dma_addr_bind_handle(txp->tx_dma_handle, 158356567907SDavid Edmondson NULL, (char *)mp->b_rptr, length, 158456567907SDavid Edmondson DDI_DMA_WRITE | DDI_DMA_STREAMING, 158556567907SDavid Edmondson DDI_DMA_DONTWAIT, 0, &dma_cookie, 158656567907SDavid Edmondson &ncookies); 1587843e1988Sjohnlev if (rc != DDI_DMA_MAPPED) { 1588843e1988Sjohnlev ASSERT(rc != DDI_DMA_INUSE); 1589843e1988Sjohnlev ASSERT(rc != DDI_DMA_PARTIAL_MAP); 159056567907SDavid Edmondson 1591843e1988Sjohnlev #ifdef XNF_DEBUG 159256567907SDavid Edmondson if (rc != DDI_DMA_NORESOURCES) 159356567907SDavid Edmondson cmn_err(CE_WARN, 159456567907SDavid Edmondson "xnf%d: bind_handle failed (%x)", 159556567907SDavid Edmondson ddi_get_instance(xnfp->xnf_devinfo), 159656567907SDavid Edmondson rc); 1597843e1988Sjohnlev #endif 159856567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 159956567907SDavid Edmondson break; 160056567907SDavid Edmondson } 160156567907SDavid Edmondson ASSERT(ncookies == 1); 160256567907SDavid Edmondson 160356567907SDavid Edmondson txp->tx_bdesc = NULL; 160456567907SDavid Edmondson txp->tx_bufp = (caddr_t)mp->b_rptr; 160556567907SDavid Edmondson txp->tx_mfn = 160656567907SDavid Edmondson xnf_btop(pa_to_ma(dma_cookie.dmac_laddress)); 160756567907SDavid Edmondson txp->tx_txreq.gref = gref_get(xnfp); 160856567907SDavid Edmondson if (txp->tx_txreq.gref == INVALID_GRANT_REF) { 160956567907SDavid Edmondson (void) ddi_dma_unbind_handle( 161056567907SDavid Edmondson txp->tx_dma_handle); 161156567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 161256567907SDavid Edmondson break; 161356567907SDavid Edmondson } 161456567907SDavid Edmondson gnttab_grant_foreign_access_ref(txp->tx_txreq.gref, 161556567907SDavid Edmondson oeid, txp->tx_mfn, 1); 1616843e1988Sjohnlev } 1617843e1988Sjohnlev 161856567907SDavid Edmondson txp->tx_next = NULL; 161956567907SDavid Edmondson txp->tx_mp = mp; 162056567907SDavid Edmondson txp->tx_txreq.size = length; 162156567907SDavid Edmondson txp->tx_txreq.offset = (uintptr_t)txp->tx_bufp & PAGEOFFSET; 162256567907SDavid Edmondson txp->tx_txreq.flags = 0; 16230dc2366fSVenugopal Iyer mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &pflags); 1624843e1988Sjohnlev if (pflags != 0) { 1625843e1988Sjohnlev /* 1626843e1988Sjohnlev * If the local protocol stack requests checksum 1627843e1988Sjohnlev * offload we set the 'checksum blank' flag, 1628843e1988Sjohnlev * indicating to the peer that we need the checksum 1629843e1988Sjohnlev * calculated for us. 1630843e1988Sjohnlev * 1631843e1988Sjohnlev * We _don't_ set the validated flag, because we haven't 1632843e1988Sjohnlev * validated that the data and the checksum match. 1633843e1988Sjohnlev */ 163456567907SDavid Edmondson xnf_pseudo_cksum(txp->tx_bufp, length); 163556567907SDavid Edmondson txp->tx_txreq.flags |= NETTXF_csum_blank; 163656567907SDavid Edmondson 1637551bc2a6Smrj xnfp->xnf_stat_tx_cksum_deferred++; 1638843e1988Sjohnlev } 1639843e1988Sjohnlev 164056567907SDavid Edmondson if (head == NULL) { 164156567907SDavid Edmondson ASSERT(tail == NULL); 1642843e1988Sjohnlev 164356567907SDavid Edmondson head = txp; 164456567907SDavid Edmondson } else { 164556567907SDavid Edmondson ASSERT(tail != NULL); 1646843e1988Sjohnlev 164756567907SDavid Edmondson tail->tx_next = txp; 1648843e1988Sjohnlev } 164956567907SDavid Edmondson tail = txp; 1650843e1988Sjohnlev 165156567907SDavid Edmondson mp = mp->b_next; 165256567907SDavid Edmondson prepared++; 1653843e1988Sjohnlev 1654843e1988Sjohnlev /* 165556567907SDavid Edmondson * There is no point in preparing more than 165656567907SDavid Edmondson * NET_TX_RING_SIZE, as we won't be able to push them 165756567907SDavid Edmondson * into the ring in one go and would hence have to 165856567907SDavid Edmondson * un-prepare the extra. 1659843e1988Sjohnlev */ 166056567907SDavid Edmondson if (prepared == NET_TX_RING_SIZE) 1661843e1988Sjohnlev break; 1662843e1988Sjohnlev } 1663843e1988Sjohnlev 166456567907SDavid Edmondson DTRACE_PROBE1(xnf_send_prepared, int, prepared); 166556567907SDavid Edmondson 166656567907SDavid Edmondson if (mp != NULL) { 166756567907SDavid Edmondson #ifdef XNF_DEBUG 166856567907SDavid Edmondson int notprepared = 0; 166956567907SDavid Edmondson mblk_t *l = mp; 167056567907SDavid Edmondson 167156567907SDavid Edmondson while (l != NULL) { 167256567907SDavid Edmondson notprepared++; 167356567907SDavid Edmondson l = l->b_next; 1674843e1988Sjohnlev } 1675843e1988Sjohnlev 167656567907SDavid Edmondson DTRACE_PROBE1(xnf_send_notprepared, int, notprepared); 167756567907SDavid Edmondson #else /* !XNF_DEBUG */ 167856567907SDavid Edmondson DTRACE_PROBE1(xnf_send_notprepared, int, -1); 167956567907SDavid Edmondson #endif /* XNF_DEBUG */ 168066f1a35aSschuster } 1681843e1988Sjohnlev 168256567907SDavid Edmondson /* 168356567907SDavid Edmondson * Push the packets we have prepared into the ring. They may 168456567907SDavid Edmondson * not all go. 168556567907SDavid Edmondson */ 168656567907SDavid Edmondson if (head != NULL) 168756567907SDavid Edmondson head = tx_push_packets(xnfp, head); 168856567907SDavid Edmondson 168956567907SDavid Edmondson /* 169056567907SDavid Edmondson * If some packets that we prepared were not sent, unprepare 169156567907SDavid Edmondson * them and add them back to the head of those we didn't 169256567907SDavid Edmondson * prepare. 169356567907SDavid Edmondson */ 169456567907SDavid Edmondson { 169556567907SDavid Edmondson xnf_txbuf_t *loop; 169656567907SDavid Edmondson mblk_t *mp_head, *mp_tail; 169756567907SDavid Edmondson int unprepared = 0; 169856567907SDavid Edmondson 169956567907SDavid Edmondson mp_head = mp_tail = NULL; 170056567907SDavid Edmondson loop = head; 170156567907SDavid Edmondson 170256567907SDavid Edmondson while (loop != NULL) { 170356567907SDavid Edmondson xnf_txbuf_t *next = loop->tx_next; 170456567907SDavid Edmondson 170556567907SDavid Edmondson if (loop->tx_bdesc == NULL) { 170656567907SDavid Edmondson (void) gnttab_end_foreign_access_ref( 170756567907SDavid Edmondson loop->tx_txreq.gref, 1); 170856567907SDavid Edmondson gref_put(xnfp, loop->tx_txreq.gref); 170956567907SDavid Edmondson (void) ddi_dma_unbind_handle( 171056567907SDavid Edmondson loop->tx_dma_handle); 171156567907SDavid Edmondson } else { 171256567907SDavid Edmondson xnf_buf_put(xnfp, loop->tx_bdesc, B_TRUE); 171356567907SDavid Edmondson } 171456567907SDavid Edmondson 171556567907SDavid Edmondson ASSERT(loop->tx_mp != NULL); 171656567907SDavid Edmondson if (mp_head == NULL) 171756567907SDavid Edmondson mp_head = loop->tx_mp; 171856567907SDavid Edmondson mp_tail = loop->tx_mp; 171956567907SDavid Edmondson 172056567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, loop); 172156567907SDavid Edmondson loop = next; 172256567907SDavid Edmondson unprepared++; 172356567907SDavid Edmondson } 172456567907SDavid Edmondson 172556567907SDavid Edmondson if (mp_tail == NULL) { 172656567907SDavid Edmondson ASSERT(mp_head == NULL); 172756567907SDavid Edmondson } else { 172856567907SDavid Edmondson ASSERT(mp_head != NULL); 172956567907SDavid Edmondson 173056567907SDavid Edmondson mp_tail->b_next = mp; 173156567907SDavid Edmondson mp = mp_head; 173256567907SDavid Edmondson } 173356567907SDavid Edmondson 173456567907SDavid Edmondson DTRACE_PROBE1(xnf_send_unprepared, int, unprepared); 173556567907SDavid Edmondson } 173656567907SDavid Edmondson 173756567907SDavid Edmondson /* 173856567907SDavid Edmondson * If any mblks are left then we have deferred for some reason 173956567907SDavid Edmondson * and need to ask for a re-schedule later. This is typically 174056567907SDavid Edmondson * due to the ring filling. 174156567907SDavid Edmondson */ 174256567907SDavid Edmondson if (mp != NULL) { 174356567907SDavid Edmondson mutex_enter(&xnfp->xnf_schedlock); 1744e779793cSDavid Edmondson xnfp->xnf_need_sched = B_TRUE; 174556567907SDavid Edmondson mutex_exit(&xnfp->xnf_schedlock); 174664c5e63cSDavid Edmondson 174756567907SDavid Edmondson xnfp->xnf_stat_tx_defer++; 174856567907SDavid Edmondson } 1749843e1988Sjohnlev 1750843e1988Sjohnlev return (mp); 1751843e1988Sjohnlev } 1752843e1988Sjohnlev 1753843e1988Sjohnlev /* 175456567907SDavid Edmondson * Notification of RX packets. Currently no TX-complete interrupt is 175556567907SDavid Edmondson * used, as we clean the TX ring lazily. 1756843e1988Sjohnlev */ 1757843e1988Sjohnlev static uint_t 1758843e1988Sjohnlev xnf_intr(caddr_t arg) 1759843e1988Sjohnlev { 1760843e1988Sjohnlev xnf_t *xnfp = (xnf_t *)arg; 176156567907SDavid Edmondson mblk_t *mp; 176256567907SDavid Edmondson boolean_t need_sched, clean_ring; 1763843e1988Sjohnlev 176456567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 1765843e1988Sjohnlev 176656567907SDavid Edmondson /* 176756567907SDavid Edmondson * Interrupts before we are connected are spurious. 176856567907SDavid Edmondson */ 1769a390c5f4Scz147101 if (!xnfp->xnf_connected) { 177056567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 1771551bc2a6Smrj xnfp->xnf_stat_unclaimed_interrupts++; 1772843e1988Sjohnlev return (DDI_INTR_UNCLAIMED); 1773843e1988Sjohnlev } 1774843e1988Sjohnlev 177556567907SDavid Edmondson /* 177656567907SDavid Edmondson * Receive side processing. 177756567907SDavid Edmondson */ 177856567907SDavid Edmondson do { 177956567907SDavid Edmondson /* 178056567907SDavid Edmondson * Collect buffers from the ring. 178156567907SDavid Edmondson */ 178256567907SDavid Edmondson xnf_rx_collect(xnfp); 1783843e1988Sjohnlev 178456567907SDavid Edmondson /* 178556567907SDavid Edmondson * Interrupt me when the next receive buffer is consumed. 178656567907SDavid Edmondson */ 178756567907SDavid Edmondson xnfp->xnf_rx_ring.sring->rsp_event = 178856567907SDavid Edmondson xnfp->xnf_rx_ring.rsp_cons + 1; 178956567907SDavid Edmondson xen_mb(); 179056567907SDavid Edmondson 179156567907SDavid Edmondson } while (RING_HAS_UNCONSUMED_RESPONSES(&xnfp->xnf_rx_ring)); 179256567907SDavid Edmondson 179356567907SDavid Edmondson if (xnfp->xnf_rx_new_buffers_posted) { 179456567907SDavid Edmondson boolean_t notify; 179556567907SDavid Edmondson 179656567907SDavid Edmondson /* 179756567907SDavid Edmondson * Indicate to the peer that we have re-filled the 179856567907SDavid Edmondson * receive ring, if it cares. 179956567907SDavid Edmondson */ 180056567907SDavid Edmondson /* LINTED: constant in conditional context */ 180156567907SDavid Edmondson RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xnfp->xnf_rx_ring, notify); 180256567907SDavid Edmondson if (notify) 180356567907SDavid Edmondson ec_notify_via_evtchn(xnfp->xnf_evtchn); 180456567907SDavid Edmondson xnfp->xnf_rx_new_buffers_posted = B_FALSE; 180556567907SDavid Edmondson } 180656567907SDavid Edmondson 180756567907SDavid Edmondson mp = xnfp->xnf_rx_head; 180856567907SDavid Edmondson xnfp->xnf_rx_head = xnfp->xnf_rx_tail = NULL; 180956567907SDavid Edmondson 181056567907SDavid Edmondson xnfp->xnf_stat_interrupts++; 181156567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 1812551bc2a6Smrj 1813551bc2a6Smrj if (mp != NULL) 1814da14cebeSEric Cheng mac_rx(xnfp->xnf_mh, NULL, mp); 181564c5e63cSDavid Edmondson 1816843e1988Sjohnlev /* 181756567907SDavid Edmondson * Transmit side processing. 181856567907SDavid Edmondson * 181956567907SDavid Edmondson * If a previous transmit attempt failed or we have pending 182056567907SDavid Edmondson * multicast requests, clean the ring. 182156567907SDavid Edmondson * 182256567907SDavid Edmondson * If we previously stalled transmission and cleaning produces 182356567907SDavid Edmondson * some free slots, tell upstream to attempt sending again. 182456567907SDavid Edmondson * 182556567907SDavid Edmondson * The odd style is to avoid acquiring xnf_txlock unless we 182656567907SDavid Edmondson * will actually look inside the tx machinery. 1827843e1988Sjohnlev */ 182856567907SDavid Edmondson mutex_enter(&xnfp->xnf_schedlock); 182956567907SDavid Edmondson need_sched = xnfp->xnf_need_sched; 183056567907SDavid Edmondson clean_ring = need_sched || (xnfp->xnf_pending_multicast > 0); 183156567907SDavid Edmondson mutex_exit(&xnfp->xnf_schedlock); 183256567907SDavid Edmondson 183356567907SDavid Edmondson if (clean_ring) { 183456567907SDavid Edmondson int free_slots; 183556567907SDavid Edmondson 1836551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 183756567907SDavid Edmondson free_slots = tx_slots_get(xnfp, 0, B_FALSE); 183856567907SDavid Edmondson 183956567907SDavid Edmondson if (need_sched && (free_slots > 0)) { 184056567907SDavid Edmondson mutex_enter(&xnfp->xnf_schedlock); 184164c5e63cSDavid Edmondson xnfp->xnf_need_sched = B_FALSE; 184256567907SDavid Edmondson mutex_exit(&xnfp->xnf_schedlock); 184356567907SDavid Edmondson 184456567907SDavid Edmondson mac_tx_update(xnfp->xnf_mh); 1845843e1988Sjohnlev } 184664c5e63cSDavid Edmondson mutex_exit(&xnfp->xnf_txlock); 184756567907SDavid Edmondson } 184864c5e63cSDavid Edmondson 184964c5e63cSDavid Edmondson return (DDI_INTR_CLAIMED); 1850843e1988Sjohnlev } 1851843e1988Sjohnlev 1852843e1988Sjohnlev /* 1853843e1988Sjohnlev * xnf_start() -- start the board receiving and enable interrupts. 1854843e1988Sjohnlev */ 1855843e1988Sjohnlev static int 1856843e1988Sjohnlev xnf_start(void *arg) 1857843e1988Sjohnlev { 1858843e1988Sjohnlev xnf_t *xnfp = arg; 1859843e1988Sjohnlev 1860843e1988Sjohnlev #ifdef XNF_DEBUG 186156567907SDavid Edmondson if (xnf_debug & XNF_DEBUG_TRACE) 1862843e1988Sjohnlev printf("xnf%d start(0x%p)\n", 1863551bc2a6Smrj ddi_get_instance(xnfp->xnf_devinfo), (void *)xnfp); 1864843e1988Sjohnlev #endif 1865843e1988Sjohnlev 186656567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 1867551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 1868843e1988Sjohnlev 1869843e1988Sjohnlev /* Accept packets from above. */ 1870551bc2a6Smrj xnfp->xnf_running = B_TRUE; 1871843e1988Sjohnlev 1872551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 187356567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 1874843e1988Sjohnlev 1875843e1988Sjohnlev return (0); 1876843e1988Sjohnlev } 1877843e1988Sjohnlev 1878843e1988Sjohnlev /* xnf_stop() - disable hardware */ 1879843e1988Sjohnlev static void 1880843e1988Sjohnlev xnf_stop(void *arg) 1881843e1988Sjohnlev { 1882843e1988Sjohnlev xnf_t *xnfp = arg; 1883843e1988Sjohnlev 1884843e1988Sjohnlev #ifdef XNF_DEBUG 188556567907SDavid Edmondson if (xnf_debug & XNF_DEBUG_TRACE) 1886843e1988Sjohnlev printf("xnf%d stop(0x%p)\n", 1887551bc2a6Smrj ddi_get_instance(xnfp->xnf_devinfo), (void *)xnfp); 1888843e1988Sjohnlev #endif 1889843e1988Sjohnlev 189056567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 1891551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 1892843e1988Sjohnlev 1893551bc2a6Smrj xnfp->xnf_running = B_FALSE; 1894843e1988Sjohnlev 1895551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 189656567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 1897843e1988Sjohnlev } 1898843e1988Sjohnlev 1899843e1988Sjohnlev /* 190056567907SDavid Edmondson * Hang buffer `bdesc' on the RX ring. 1901843e1988Sjohnlev */ 1902843e1988Sjohnlev static void 190356567907SDavid Edmondson xnf_rxbuf_hang(xnf_t *xnfp, xnf_buf_t *bdesc) 1904843e1988Sjohnlev { 190556567907SDavid Edmondson netif_rx_request_t *reqp; 1906843e1988Sjohnlev RING_IDX hang_ix; 1907843e1988Sjohnlev 190856567907SDavid Edmondson ASSERT(MUTEX_HELD(&xnfp->xnf_rxlock)); 1909843e1988Sjohnlev 1910551bc2a6Smrj reqp = RING_GET_REQUEST(&xnfp->xnf_rx_ring, 1911551bc2a6Smrj xnfp->xnf_rx_ring.req_prod_pvt); 1912551bc2a6Smrj hang_ix = (RING_IDX) (reqp - RING_GET_REQUEST(&xnfp->xnf_rx_ring, 0)); 191356567907SDavid Edmondson ASSERT(xnfp->xnf_rx_pkt_info[hang_ix] == NULL); 1914551bc2a6Smrj 191556567907SDavid Edmondson reqp->id = bdesc->id = hang_ix; 1916843e1988Sjohnlev reqp->gref = bdesc->grant_ref; 1917843e1988Sjohnlev 191856567907SDavid Edmondson xnfp->xnf_rx_pkt_info[hang_ix] = bdesc; 191956567907SDavid Edmondson xnfp->xnf_rx_ring.req_prod_pvt++; 192056567907SDavid Edmondson 192156567907SDavid Edmondson xnfp->xnf_rx_new_buffers_posted = B_TRUE; 192256567907SDavid Edmondson } 1923551bc2a6Smrj 1924551bc2a6Smrj /* 192556567907SDavid Edmondson * Collect packets from the RX ring, storing them in `xnfp' for later 192656567907SDavid Edmondson * use. 192756567907SDavid Edmondson */ 192856567907SDavid Edmondson static void 192956567907SDavid Edmondson xnf_rx_collect(xnf_t *xnfp) 193056567907SDavid Edmondson { 193156567907SDavid Edmondson mblk_t *head, *tail; 193256567907SDavid Edmondson 193356567907SDavid Edmondson ASSERT(MUTEX_HELD(&xnfp->xnf_rxlock)); 193456567907SDavid Edmondson 193556567907SDavid Edmondson /* 193656567907SDavid Edmondson * Loop over unconsumed responses: 1937551bc2a6Smrj * 1. get a response 1938551bc2a6Smrj * 2. take corresponding buffer off recv. ring 1939551bc2a6Smrj * 3. indicate this by setting slot to NULL 1940551bc2a6Smrj * 4. create a new message and 1941551bc2a6Smrj * 5. copy data in, adjust ptr 1942551bc2a6Smrj */ 1943551bc2a6Smrj 1944551bc2a6Smrj head = tail = NULL; 1945551bc2a6Smrj 1946551bc2a6Smrj while (RING_HAS_UNCONSUMED_RESPONSES(&xnfp->xnf_rx_ring)) { 194756567907SDavid Edmondson netif_rx_response_t *rxpkt; 194856567907SDavid Edmondson xnf_buf_t *bdesc; 194956567907SDavid Edmondson ssize_t len; 195056567907SDavid Edmondson size_t off; 195156567907SDavid Edmondson mblk_t *mp = NULL; 195256567907SDavid Edmondson boolean_t hwcsum = B_FALSE; 195356567907SDavid Edmondson grant_ref_t ref; 1954551bc2a6Smrj 1955551bc2a6Smrj /* 1. */ 1956551bc2a6Smrj rxpkt = RING_GET_RESPONSE(&xnfp->xnf_rx_ring, 1957551bc2a6Smrj xnfp->xnf_rx_ring.rsp_cons); 1958551bc2a6Smrj 195956567907SDavid Edmondson DTRACE_PROBE4(xnf_rx_got_rsp, int, (int)rxpkt->id, 196056567907SDavid Edmondson int, (int)rxpkt->offset, 196156567907SDavid Edmondson int, (int)rxpkt->flags, 196256567907SDavid Edmondson int, (int)rxpkt->status); 1963551bc2a6Smrj 1964551bc2a6Smrj /* 1965551bc2a6Smrj * 2. 1966551bc2a6Smrj */ 196756567907SDavid Edmondson bdesc = xnfp->xnf_rx_pkt_info[rxpkt->id]; 1968551bc2a6Smrj 196956567907SDavid Edmondson /* 197056567907SDavid Edmondson * 3. 197156567907SDavid Edmondson */ 197256567907SDavid Edmondson xnfp->xnf_rx_pkt_info[rxpkt->id] = NULL; 197356567907SDavid Edmondson ASSERT(bdesc->id == rxpkt->id); 197456567907SDavid Edmondson 197556567907SDavid Edmondson ref = bdesc->grant_ref; 197656567907SDavid Edmondson off = rxpkt->offset; 197756567907SDavid Edmondson len = rxpkt->status; 197856567907SDavid Edmondson 197956567907SDavid Edmondson if (!xnfp->xnf_running) { 198056567907SDavid Edmondson DTRACE_PROBE4(xnf_rx_not_running, 198156567907SDavid Edmondson int, rxpkt->status, 1982551bc2a6Smrj char *, bdesc->buf, int, rxpkt->offset, 1983551bc2a6Smrj char *, ((char *)bdesc->buf) + rxpkt->offset); 198456567907SDavid Edmondson 198556567907SDavid Edmondson xnfp->xnf_stat_drop++; 198656567907SDavid Edmondson 198756567907SDavid Edmondson } else if (len <= 0) { 198856567907SDavid Edmondson DTRACE_PROBE4(xnf_rx_pkt_status_negative, 198956567907SDavid Edmondson int, rxpkt->status, 199056567907SDavid Edmondson char *, bdesc->buf, int, rxpkt->offset, 199156567907SDavid Edmondson char *, ((char *)bdesc->buf) + rxpkt->offset); 199256567907SDavid Edmondson 199356567907SDavid Edmondson xnfp->xnf_stat_errrx++; 199456567907SDavid Edmondson 199556567907SDavid Edmondson switch (len) { 199656567907SDavid Edmondson case 0: 199756567907SDavid Edmondson xnfp->xnf_stat_runt++; 199856567907SDavid Edmondson break; 199956567907SDavid Edmondson case NETIF_RSP_ERROR: 200056567907SDavid Edmondson xnfp->xnf_stat_mac_rcv_error++; 200156567907SDavid Edmondson break; 200256567907SDavid Edmondson case NETIF_RSP_DROPPED: 200356567907SDavid Edmondson xnfp->xnf_stat_norxbuf++; 200456567907SDavid Edmondson break; 2005551bc2a6Smrj } 200656567907SDavid Edmondson 200756567907SDavid Edmondson } else if (bdesc->grant_ref == INVALID_GRANT_REF) { 200856567907SDavid Edmondson cmn_err(CE_WARN, "Bad rx grant reference %d " 200956567907SDavid Edmondson "from domain %d", ref, 201056567907SDavid Edmondson xvdi_get_oeid(xnfp->xnf_devinfo)); 201156567907SDavid Edmondson 201256567907SDavid Edmondson } else if ((off + len) > PAGESIZE) { 201356567907SDavid Edmondson cmn_err(CE_WARN, "Rx packet overflows page " 201456567907SDavid Edmondson "(offset %ld, length %ld) from domain %d", 201556567907SDavid Edmondson off, len, xvdi_get_oeid(xnfp->xnf_devinfo)); 201656567907SDavid Edmondson } else { 201756567907SDavid Edmondson xnf_buf_t *nbuf = NULL; 201856567907SDavid Edmondson 201956567907SDavid Edmondson DTRACE_PROBE4(xnf_rx_packet, int, len, 202056567907SDavid Edmondson char *, bdesc->buf, int, off, 202156567907SDavid Edmondson char *, ((char *)bdesc->buf) + off); 202256567907SDavid Edmondson 202356567907SDavid Edmondson ASSERT(off + len <= PAGEOFFSET); 202456567907SDavid Edmondson 2025551bc2a6Smrj if (rxpkt->flags & NETRXF_data_validated) 2026551bc2a6Smrj hwcsum = B_TRUE; 2027551bc2a6Smrj 2028551bc2a6Smrj /* 202956567907SDavid Edmondson * If the packet is below a pre-determined 203056567907SDavid Edmondson * size we will copy data out rather than 203156567907SDavid Edmondson * replace it. 2032551bc2a6Smrj */ 203356567907SDavid Edmondson if (len > xnf_rx_copy_limit) 203456567907SDavid Edmondson nbuf = xnf_buf_get(xnfp, KM_NOSLEEP, B_FALSE); 203556567907SDavid Edmondson 2036551bc2a6Smrj /* 203756567907SDavid Edmondson * If we have a replacement buffer, attempt to 203856567907SDavid Edmondson * wrap the existing one with an mblk_t in 203956567907SDavid Edmondson * order that the upper layers of the stack 204056567907SDavid Edmondson * might use it directly. 2041551bc2a6Smrj */ 204256567907SDavid Edmondson if (nbuf != NULL) { 204356567907SDavid Edmondson mp = desballoc((unsigned char *)bdesc->buf, 204456567907SDavid Edmondson bdesc->len, 0, &bdesc->free_rtn); 204556567907SDavid Edmondson if (mp == NULL) { 204656567907SDavid Edmondson xnfp->xnf_stat_rx_desballoc_fail++; 2047551bc2a6Smrj xnfp->xnf_stat_norxbuf++; 204856567907SDavid Edmondson 204956567907SDavid Edmondson xnf_buf_put(xnfp, nbuf, B_FALSE); 205056567907SDavid Edmondson nbuf = NULL; 205156567907SDavid Edmondson } else { 205256567907SDavid Edmondson mp->b_rptr = mp->b_rptr + off; 205356567907SDavid Edmondson mp->b_wptr = mp->b_rptr + len; 205456567907SDavid Edmondson 205556567907SDavid Edmondson /* 205656567907SDavid Edmondson * Release the grant reference 205756567907SDavid Edmondson * associated with this buffer 205856567907SDavid Edmondson * - they are scarce and the 205956567907SDavid Edmondson * upper layers of the stack 206056567907SDavid Edmondson * don't need it. 206156567907SDavid Edmondson */ 206256567907SDavid Edmondson (void) gnttab_end_foreign_access_ref( 206356567907SDavid Edmondson bdesc->grant_ref, 0); 206456567907SDavid Edmondson gref_put(xnfp, bdesc->grant_ref); 206556567907SDavid Edmondson bdesc->grant_ref = INVALID_GRANT_REF; 206656567907SDavid Edmondson 206756567907SDavid Edmondson bdesc = nbuf; 206856567907SDavid Edmondson } 206956567907SDavid Edmondson } 207056567907SDavid Edmondson 207156567907SDavid Edmondson if (nbuf == NULL) { 207256567907SDavid Edmondson /* 207356567907SDavid Edmondson * No replacement buffer allocated - 207456567907SDavid Edmondson * attempt to copy the data out and 207556567907SDavid Edmondson * re-hang the existing buffer. 207656567907SDavid Edmondson */ 207756567907SDavid Edmondson 207856567907SDavid Edmondson /* 4. */ 207956567907SDavid Edmondson mp = allocb(len, BPRI_MED); 208056567907SDavid Edmondson if (mp == NULL) { 208156567907SDavid Edmondson xnfp->xnf_stat_rx_allocb_fail++; 208256567907SDavid Edmondson xnfp->xnf_stat_norxbuf++; 2083551bc2a6Smrj } else { 2084551bc2a6Smrj /* 5. */ 2085551bc2a6Smrj bcopy(bdesc->buf + off, mp->b_wptr, 2086551bc2a6Smrj len); 2087551bc2a6Smrj mp->b_wptr += len; 2088551bc2a6Smrj } 2089551bc2a6Smrj } 2090551bc2a6Smrj } 2091551bc2a6Smrj 209256567907SDavid Edmondson /* Re-hang the buffer. */ 209356567907SDavid Edmondson xnf_rxbuf_hang(xnfp, bdesc); 2094551bc2a6Smrj 209556567907SDavid Edmondson if (mp != NULL) { 2096843e1988Sjohnlev if (hwcsum) { 2097843e1988Sjohnlev /* 2098843e1988Sjohnlev * If the peer says that the data has 2099843e1988Sjohnlev * been validated then we declare that 2100843e1988Sjohnlev * the full checksum has been 2101843e1988Sjohnlev * verified. 2102843e1988Sjohnlev * 2103843e1988Sjohnlev * We don't look at the "checksum 2104843e1988Sjohnlev * blank" flag, and hence could have a 2105843e1988Sjohnlev * packet here that we are asserting 2106843e1988Sjohnlev * is good with a blank checksum. 2107843e1988Sjohnlev */ 21080dc2366fSVenugopal Iyer mac_hcksum_set(mp, 0, 0, 0, 0, 21090dc2366fSVenugopal Iyer HCK_FULLCKSUM_OK); 2110551bc2a6Smrj xnfp->xnf_stat_rx_cksum_no_need++; 2111843e1988Sjohnlev } 2112843e1988Sjohnlev if (head == NULL) { 211356567907SDavid Edmondson ASSERT(tail == NULL); 211456567907SDavid Edmondson 211556567907SDavid Edmondson head = mp; 2116843e1988Sjohnlev } else { 211756567907SDavid Edmondson ASSERT(tail != NULL); 211856567907SDavid Edmondson 2119843e1988Sjohnlev tail->b_next = mp; 2120843e1988Sjohnlev } 212156567907SDavid Edmondson tail = mp; 2122843e1988Sjohnlev 2123843e1988Sjohnlev ASSERT(mp->b_next == NULL); 2124843e1988Sjohnlev 2125551bc2a6Smrj xnfp->xnf_stat_ipackets++; 2126551bc2a6Smrj xnfp->xnf_stat_rbytes += len; 2127843e1988Sjohnlev } 2128843e1988Sjohnlev 2129551bc2a6Smrj xnfp->xnf_rx_ring.rsp_cons++; 2130843e1988Sjohnlev } 2131843e1988Sjohnlev 2132843e1988Sjohnlev /* 213356567907SDavid Edmondson * Store the mblks we have collected. 2134843e1988Sjohnlev */ 213556567907SDavid Edmondson if (head != NULL) { 213656567907SDavid Edmondson ASSERT(tail != NULL); 2137843e1988Sjohnlev 213856567907SDavid Edmondson if (xnfp->xnf_rx_head == NULL) { 213956567907SDavid Edmondson ASSERT(xnfp->xnf_rx_tail == NULL); 2140843e1988Sjohnlev 214156567907SDavid Edmondson xnfp->xnf_rx_head = head; 2142843e1988Sjohnlev } else { 214356567907SDavid Edmondson ASSERT(xnfp->xnf_rx_tail != NULL); 214456567907SDavid Edmondson 214556567907SDavid Edmondson xnfp->xnf_rx_tail->b_next = head; 214656567907SDavid Edmondson } 214756567907SDavid Edmondson xnfp->xnf_rx_tail = tail; 2148843e1988Sjohnlev } 2149843e1988Sjohnlev } 2150843e1988Sjohnlev 2151843e1988Sjohnlev /* 2152843e1988Sjohnlev * xnf_alloc_dma_resources() -- initialize the drivers structures 2153843e1988Sjohnlev */ 2154843e1988Sjohnlev static int 2155843e1988Sjohnlev xnf_alloc_dma_resources(xnf_t *xnfp) 2156843e1988Sjohnlev { 2157551bc2a6Smrj dev_info_t *devinfo = xnfp->xnf_devinfo; 2158843e1988Sjohnlev size_t len; 2159843e1988Sjohnlev ddi_dma_cookie_t dma_cookie; 2160843e1988Sjohnlev uint_t ncookies; 2161843e1988Sjohnlev int rc; 2162843e1988Sjohnlev caddr_t rptr; 2163843e1988Sjohnlev 2164843e1988Sjohnlev /* 2165843e1988Sjohnlev * The code below allocates all the DMA data structures that 2166843e1988Sjohnlev * need to be released when the driver is detached. 2167843e1988Sjohnlev * 2168843e1988Sjohnlev * Allocate page for the transmit descriptor ring. 2169843e1988Sjohnlev */ 2170843e1988Sjohnlev if (ddi_dma_alloc_handle(devinfo, &ringbuf_dma_attr, 2171551bc2a6Smrj DDI_DMA_SLEEP, 0, &xnfp->xnf_tx_ring_dma_handle) != DDI_SUCCESS) 2172843e1988Sjohnlev goto alloc_error; 2173843e1988Sjohnlev 2174551bc2a6Smrj if (ddi_dma_mem_alloc(xnfp->xnf_tx_ring_dma_handle, 2175843e1988Sjohnlev PAGESIZE, &accattr, DDI_DMA_CONSISTENT, 2176843e1988Sjohnlev DDI_DMA_SLEEP, 0, &rptr, &len, 2177551bc2a6Smrj &xnfp->xnf_tx_ring_dma_acchandle) != DDI_SUCCESS) { 2178551bc2a6Smrj ddi_dma_free_handle(&xnfp->xnf_tx_ring_dma_handle); 2179551bc2a6Smrj xnfp->xnf_tx_ring_dma_handle = NULL; 2180843e1988Sjohnlev goto alloc_error; 2181843e1988Sjohnlev } 2182843e1988Sjohnlev 2183551bc2a6Smrj if ((rc = ddi_dma_addr_bind_handle(xnfp->xnf_tx_ring_dma_handle, NULL, 2184843e1988Sjohnlev rptr, PAGESIZE, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 2185843e1988Sjohnlev DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies)) != DDI_DMA_MAPPED) { 2186551bc2a6Smrj ddi_dma_mem_free(&xnfp->xnf_tx_ring_dma_acchandle); 2187551bc2a6Smrj ddi_dma_free_handle(&xnfp->xnf_tx_ring_dma_handle); 2188551bc2a6Smrj xnfp->xnf_tx_ring_dma_handle = NULL; 2189551bc2a6Smrj xnfp->xnf_tx_ring_dma_acchandle = NULL; 2190843e1988Sjohnlev if (rc == DDI_DMA_NORESOURCES) 2191843e1988Sjohnlev goto alloc_error; 2192843e1988Sjohnlev else 2193843e1988Sjohnlev goto error; 2194843e1988Sjohnlev } 2195843e1988Sjohnlev 2196843e1988Sjohnlev ASSERT(ncookies == 1); 2197843e1988Sjohnlev bzero(rptr, PAGESIZE); 2198843e1988Sjohnlev /* LINTED: constant in conditional context */ 2199843e1988Sjohnlev SHARED_RING_INIT((netif_tx_sring_t *)rptr); 2200843e1988Sjohnlev /* LINTED: constant in conditional context */ 2201551bc2a6Smrj FRONT_RING_INIT(&xnfp->xnf_tx_ring, (netif_tx_sring_t *)rptr, PAGESIZE); 2202551bc2a6Smrj xnfp->xnf_tx_ring_phys_addr = dma_cookie.dmac_laddress; 2203843e1988Sjohnlev 2204843e1988Sjohnlev /* 2205843e1988Sjohnlev * Allocate page for the receive descriptor ring. 2206843e1988Sjohnlev */ 2207843e1988Sjohnlev if (ddi_dma_alloc_handle(devinfo, &ringbuf_dma_attr, 2208551bc2a6Smrj DDI_DMA_SLEEP, 0, &xnfp->xnf_rx_ring_dma_handle) != DDI_SUCCESS) 2209843e1988Sjohnlev goto alloc_error; 2210843e1988Sjohnlev 2211551bc2a6Smrj if (ddi_dma_mem_alloc(xnfp->xnf_rx_ring_dma_handle, 2212843e1988Sjohnlev PAGESIZE, &accattr, DDI_DMA_CONSISTENT, 2213843e1988Sjohnlev DDI_DMA_SLEEP, 0, &rptr, &len, 2214551bc2a6Smrj &xnfp->xnf_rx_ring_dma_acchandle) != DDI_SUCCESS) { 2215551bc2a6Smrj ddi_dma_free_handle(&xnfp->xnf_rx_ring_dma_handle); 2216551bc2a6Smrj xnfp->xnf_rx_ring_dma_handle = NULL; 2217843e1988Sjohnlev goto alloc_error; 2218843e1988Sjohnlev } 2219843e1988Sjohnlev 2220551bc2a6Smrj if ((rc = ddi_dma_addr_bind_handle(xnfp->xnf_rx_ring_dma_handle, NULL, 2221843e1988Sjohnlev rptr, PAGESIZE, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 2222843e1988Sjohnlev DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies)) != DDI_DMA_MAPPED) { 2223551bc2a6Smrj ddi_dma_mem_free(&xnfp->xnf_rx_ring_dma_acchandle); 2224551bc2a6Smrj ddi_dma_free_handle(&xnfp->xnf_rx_ring_dma_handle); 2225551bc2a6Smrj xnfp->xnf_rx_ring_dma_handle = NULL; 2226551bc2a6Smrj xnfp->xnf_rx_ring_dma_acchandle = NULL; 2227843e1988Sjohnlev if (rc == DDI_DMA_NORESOURCES) 2228843e1988Sjohnlev goto alloc_error; 2229843e1988Sjohnlev else 2230843e1988Sjohnlev goto error; 2231843e1988Sjohnlev } 2232843e1988Sjohnlev 2233843e1988Sjohnlev ASSERT(ncookies == 1); 2234843e1988Sjohnlev bzero(rptr, PAGESIZE); 2235843e1988Sjohnlev /* LINTED: constant in conditional context */ 2236843e1988Sjohnlev SHARED_RING_INIT((netif_rx_sring_t *)rptr); 2237843e1988Sjohnlev /* LINTED: constant in conditional context */ 2238551bc2a6Smrj FRONT_RING_INIT(&xnfp->xnf_rx_ring, (netif_rx_sring_t *)rptr, PAGESIZE); 2239551bc2a6Smrj xnfp->xnf_rx_ring_phys_addr = dma_cookie.dmac_laddress; 2240843e1988Sjohnlev 2241843e1988Sjohnlev return (DDI_SUCCESS); 2242843e1988Sjohnlev 2243843e1988Sjohnlev alloc_error: 2244843e1988Sjohnlev cmn_err(CE_WARN, "xnf%d: could not allocate enough DMA memory", 2245551bc2a6Smrj ddi_get_instance(xnfp->xnf_devinfo)); 2246843e1988Sjohnlev error: 2247843e1988Sjohnlev xnf_release_dma_resources(xnfp); 2248843e1988Sjohnlev return (DDI_FAILURE); 2249843e1988Sjohnlev } 2250843e1988Sjohnlev 2251843e1988Sjohnlev /* 2252843e1988Sjohnlev * Release all DMA resources in the opposite order from acquisition 2253843e1988Sjohnlev */ 2254843e1988Sjohnlev static void 2255843e1988Sjohnlev xnf_release_dma_resources(xnf_t *xnfp) 2256843e1988Sjohnlev { 2257843e1988Sjohnlev int i; 2258843e1988Sjohnlev 2259843e1988Sjohnlev /* 2260843e1988Sjohnlev * Free receive buffers which are currently associated with 226156567907SDavid Edmondson * descriptors. 2262843e1988Sjohnlev */ 226356567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 226456567907SDavid Edmondson for (i = 0; i < NET_RX_RING_SIZE; i++) { 226556567907SDavid Edmondson xnf_buf_t *bp; 2266843e1988Sjohnlev 226756567907SDavid Edmondson if ((bp = xnfp->xnf_rx_pkt_info[i]) == NULL) 2268843e1988Sjohnlev continue; 226956567907SDavid Edmondson xnfp->xnf_rx_pkt_info[i] = NULL; 227056567907SDavid Edmondson xnf_buf_put(xnfp, bp, B_FALSE); 2271843e1988Sjohnlev } 227256567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 2273843e1988Sjohnlev 227456567907SDavid Edmondson /* Free the receive ring buffer. */ 2275551bc2a6Smrj if (xnfp->xnf_rx_ring_dma_acchandle != NULL) { 2276551bc2a6Smrj (void) ddi_dma_unbind_handle(xnfp->xnf_rx_ring_dma_handle); 2277551bc2a6Smrj ddi_dma_mem_free(&xnfp->xnf_rx_ring_dma_acchandle); 2278551bc2a6Smrj ddi_dma_free_handle(&xnfp->xnf_rx_ring_dma_handle); 2279551bc2a6Smrj xnfp->xnf_rx_ring_dma_acchandle = NULL; 2280843e1988Sjohnlev } 228156567907SDavid Edmondson /* Free the transmit ring buffer. */ 2282551bc2a6Smrj if (xnfp->xnf_tx_ring_dma_acchandle != NULL) { 2283551bc2a6Smrj (void) ddi_dma_unbind_handle(xnfp->xnf_tx_ring_dma_handle); 2284551bc2a6Smrj ddi_dma_mem_free(&xnfp->xnf_tx_ring_dma_acchandle); 2285551bc2a6Smrj ddi_dma_free_handle(&xnfp->xnf_tx_ring_dma_handle); 2286551bc2a6Smrj xnfp->xnf_tx_ring_dma_acchandle = NULL; 2287843e1988Sjohnlev } 2288a390c5f4Scz147101 228956567907SDavid Edmondson } 229056567907SDavid Edmondson 2291a390c5f4Scz147101 /* 229256567907SDavid Edmondson * Release any packets and associated structures used by the TX ring. 2293a390c5f4Scz147101 */ 2294843e1988Sjohnlev static void 2295843e1988Sjohnlev xnf_release_mblks(xnf_t *xnfp) 2296843e1988Sjohnlev { 229756567907SDavid Edmondson RING_IDX i; 229856567907SDavid Edmondson xnf_txid_t *tidp; 2299843e1988Sjohnlev 230056567907SDavid Edmondson for (i = 0, tidp = &xnfp->xnf_tx_pkt_id[0]; 230156567907SDavid Edmondson i < NET_TX_RING_SIZE; 230256567907SDavid Edmondson i++, tidp++) { 230356567907SDavid Edmondson xnf_txbuf_t *txp = tidp->txbuf; 230456567907SDavid Edmondson 230556567907SDavid Edmondson if (txp != NULL) { 230656567907SDavid Edmondson ASSERT(txp->tx_mp != NULL); 230756567907SDavid Edmondson freemsg(txp->tx_mp); 230856567907SDavid Edmondson 230956567907SDavid Edmondson txid_put(xnfp, tidp); 231056567907SDavid Edmondson kmem_cache_free(xnfp->xnf_tx_buf_cache, txp); 231156567907SDavid Edmondson } 2312843e1988Sjohnlev } 2313843e1988Sjohnlev } 2314843e1988Sjohnlev 231556567907SDavid Edmondson static int 231656567907SDavid Edmondson xnf_buf_constructor(void *buf, void *arg, int kmflag) 2317843e1988Sjohnlev { 231856567907SDavid Edmondson int (*ddiflags)(caddr_t) = DDI_DMA_SLEEP; 231956567907SDavid Edmondson xnf_buf_t *bdesc = buf; 232056567907SDavid Edmondson xnf_t *xnfp = arg; 2321843e1988Sjohnlev ddi_dma_cookie_t dma_cookie; 232256567907SDavid Edmondson uint_t ncookies; 232356567907SDavid Edmondson size_t len; 2324843e1988Sjohnlev 232556567907SDavid Edmondson if (kmflag & KM_NOSLEEP) 232656567907SDavid Edmondson ddiflags = DDI_DMA_DONTWAIT; 2327843e1988Sjohnlev 232856567907SDavid Edmondson /* Allocate a DMA access handle for the buffer. */ 232956567907SDavid Edmondson if (ddi_dma_alloc_handle(xnfp->xnf_devinfo, &buf_dma_attr, 233056567907SDavid Edmondson ddiflags, 0, &bdesc->dma_handle) != DDI_SUCCESS) 2331843e1988Sjohnlev goto failure; 2332843e1988Sjohnlev 233356567907SDavid Edmondson /* Allocate DMA-able memory for buffer. */ 2334843e1988Sjohnlev if (ddi_dma_mem_alloc(bdesc->dma_handle, 233556567907SDavid Edmondson PAGESIZE, &data_accattr, DDI_DMA_STREAMING, ddiflags, 0, 2336843e1988Sjohnlev &bdesc->buf, &len, &bdesc->acc_handle) != DDI_SUCCESS) 2337551bc2a6Smrj goto failure_1; 2338843e1988Sjohnlev 233956567907SDavid Edmondson /* Bind to virtual address of buffer to get physical address. */ 2340843e1988Sjohnlev if (ddi_dma_addr_bind_handle(bdesc->dma_handle, NULL, 234156567907SDavid Edmondson bdesc->buf, len, DDI_DMA_RDWR | DDI_DMA_STREAMING, 234256567907SDavid Edmondson ddiflags, 0, &dma_cookie, &ncookies) != DDI_DMA_MAPPED) 2343551bc2a6Smrj goto failure_2; 2344843e1988Sjohnlev ASSERT(ncookies == 1); 2345843e1988Sjohnlev 234656567907SDavid Edmondson bdesc->free_rtn.free_func = xnf_buf_recycle; 234756567907SDavid Edmondson bdesc->free_rtn.free_arg = (caddr_t)bdesc; 234856567907SDavid Edmondson bdesc->xnfp = xnfp; 234956567907SDavid Edmondson bdesc->buf_phys = dma_cookie.dmac_laddress; 235056567907SDavid Edmondson bdesc->buf_mfn = pfn_to_mfn(xnf_btop(bdesc->buf_phys)); 235156567907SDavid Edmondson bdesc->len = dma_cookie.dmac_size; 235256567907SDavid Edmondson bdesc->grant_ref = INVALID_GRANT_REF; 235356567907SDavid Edmondson bdesc->gen = xnfp->xnf_gen; 2354551bc2a6Smrj 2355*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&xnfp->xnf_stat_buf_allocated); 2356843e1988Sjohnlev 235756567907SDavid Edmondson return (0); 2358843e1988Sjohnlev 2359551bc2a6Smrj failure_2: 2360843e1988Sjohnlev ddi_dma_mem_free(&bdesc->acc_handle); 2361843e1988Sjohnlev 2362551bc2a6Smrj failure_1: 2363843e1988Sjohnlev ddi_dma_free_handle(&bdesc->dma_handle); 2364843e1988Sjohnlev 2365843e1988Sjohnlev failure: 236656567907SDavid Edmondson 2367fd0939efSDavid Edmondson ASSERT(kmflag & KM_NOSLEEP); /* Cannot fail for KM_SLEEP. */ 236856567907SDavid Edmondson return (-1); 236956567907SDavid Edmondson } 237056567907SDavid Edmondson 237156567907SDavid Edmondson static void 237256567907SDavid Edmondson xnf_buf_destructor(void *buf, void *arg) 237356567907SDavid Edmondson { 237456567907SDavid Edmondson xnf_buf_t *bdesc = buf; 237556567907SDavid Edmondson xnf_t *xnfp = arg; 237656567907SDavid Edmondson 237756567907SDavid Edmondson (void) ddi_dma_unbind_handle(bdesc->dma_handle); 237856567907SDavid Edmondson ddi_dma_mem_free(&bdesc->acc_handle); 237956567907SDavid Edmondson ddi_dma_free_handle(&bdesc->dma_handle); 238056567907SDavid Edmondson 2381*1a5e258fSJosef 'Jeff' Sipek atomic_dec_64(&xnfp->xnf_stat_buf_allocated); 238256567907SDavid Edmondson } 238356567907SDavid Edmondson 238456567907SDavid Edmondson static xnf_buf_t * 238556567907SDavid Edmondson xnf_buf_get(xnf_t *xnfp, int flags, boolean_t readonly) 238656567907SDavid Edmondson { 238756567907SDavid Edmondson grant_ref_t gref; 238856567907SDavid Edmondson xnf_buf_t *bufp; 238956567907SDavid Edmondson 239056567907SDavid Edmondson /* 239156567907SDavid Edmondson * Usually grant references are more scarce than memory, so we 239256567907SDavid Edmondson * attempt to acquire a grant reference first. 239356567907SDavid Edmondson */ 239456567907SDavid Edmondson gref = gref_get(xnfp); 239556567907SDavid Edmondson if (gref == INVALID_GRANT_REF) 2396843e1988Sjohnlev return (NULL); 239756567907SDavid Edmondson 239856567907SDavid Edmondson bufp = kmem_cache_alloc(xnfp->xnf_buf_cache, flags); 239956567907SDavid Edmondson if (bufp == NULL) { 240056567907SDavid Edmondson gref_put(xnfp, gref); 240156567907SDavid Edmondson return (NULL); 240256567907SDavid Edmondson } 240356567907SDavid Edmondson 240456567907SDavid Edmondson ASSERT(bufp->grant_ref == INVALID_GRANT_REF); 240556567907SDavid Edmondson 240656567907SDavid Edmondson bufp->grant_ref = gref; 240756567907SDavid Edmondson 240856567907SDavid Edmondson if (bufp->gen != xnfp->xnf_gen) 240956567907SDavid Edmondson xnf_buf_refresh(bufp); 241056567907SDavid Edmondson 241156567907SDavid Edmondson gnttab_grant_foreign_access_ref(bufp->grant_ref, 241256567907SDavid Edmondson xvdi_get_oeid(bufp->xnfp->xnf_devinfo), 241356567907SDavid Edmondson bufp->buf_mfn, readonly ? 1 : 0); 241456567907SDavid Edmondson 2415*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&xnfp->xnf_stat_buf_outstanding); 241656567907SDavid Edmondson 241756567907SDavid Edmondson return (bufp); 241856567907SDavid Edmondson } 241956567907SDavid Edmondson 242056567907SDavid Edmondson static void 242156567907SDavid Edmondson xnf_buf_put(xnf_t *xnfp, xnf_buf_t *bufp, boolean_t readonly) 242256567907SDavid Edmondson { 242356567907SDavid Edmondson if (bufp->grant_ref != INVALID_GRANT_REF) { 242456567907SDavid Edmondson (void) gnttab_end_foreign_access_ref( 242556567907SDavid Edmondson bufp->grant_ref, readonly ? 1 : 0); 242656567907SDavid Edmondson gref_put(xnfp, bufp->grant_ref); 242756567907SDavid Edmondson bufp->grant_ref = INVALID_GRANT_REF; 242856567907SDavid Edmondson } 242956567907SDavid Edmondson 243056567907SDavid Edmondson kmem_cache_free(xnfp->xnf_buf_cache, bufp); 243156567907SDavid Edmondson 2432*1a5e258fSJosef 'Jeff' Sipek atomic_dec_64(&xnfp->xnf_stat_buf_outstanding); 243356567907SDavid Edmondson } 243456567907SDavid Edmondson 243556567907SDavid Edmondson /* 243656567907SDavid Edmondson * Refresh any cached data about a buffer after resume. 243756567907SDavid Edmondson */ 243856567907SDavid Edmondson static void 243956567907SDavid Edmondson xnf_buf_refresh(xnf_buf_t *bdesc) 244056567907SDavid Edmondson { 244156567907SDavid Edmondson bdesc->buf_mfn = pfn_to_mfn(xnf_btop(bdesc->buf_phys)); 244256567907SDavid Edmondson bdesc->gen = bdesc->xnfp->xnf_gen; 244356567907SDavid Edmondson } 244456567907SDavid Edmondson 244556567907SDavid Edmondson /* 244656567907SDavid Edmondson * Streams `freeb' routine for `xnf_buf_t' when used as transmit 244756567907SDavid Edmondson * look-aside buffers. 244856567907SDavid Edmondson */ 244956567907SDavid Edmondson static void 245056567907SDavid Edmondson xnf_buf_recycle(xnf_buf_t *bdesc) 245156567907SDavid Edmondson { 245256567907SDavid Edmondson xnf_t *xnfp = bdesc->xnfp; 245356567907SDavid Edmondson 245456567907SDavid Edmondson xnf_buf_put(xnfp, bdesc, B_TRUE); 245556567907SDavid Edmondson } 245656567907SDavid Edmondson 245756567907SDavid Edmondson static int 245856567907SDavid Edmondson xnf_tx_buf_constructor(void *buf, void *arg, int kmflag) 245956567907SDavid Edmondson { 2460fd0939efSDavid Edmondson int (*ddiflags)(caddr_t) = DDI_DMA_SLEEP; 246156567907SDavid Edmondson xnf_txbuf_t *txp = buf; 246256567907SDavid Edmondson xnf_t *xnfp = arg; 246356567907SDavid Edmondson 2464fd0939efSDavid Edmondson if (kmflag & KM_NOSLEEP) 2465fd0939efSDavid Edmondson ddiflags = DDI_DMA_DONTWAIT; 2466fd0939efSDavid Edmondson 246756567907SDavid Edmondson if (ddi_dma_alloc_handle(xnfp->xnf_devinfo, &buf_dma_attr, 2468fd0939efSDavid Edmondson ddiflags, 0, &txp->tx_dma_handle) != DDI_SUCCESS) { 2469fd0939efSDavid Edmondson ASSERT(kmflag & KM_NOSLEEP); /* Cannot fail for KM_SLEEP. */ 247056567907SDavid Edmondson return (-1); 2471fd0939efSDavid Edmondson } 247256567907SDavid Edmondson 247356567907SDavid Edmondson return (0); 247456567907SDavid Edmondson } 247556567907SDavid Edmondson 247656567907SDavid Edmondson static void 247756567907SDavid Edmondson xnf_tx_buf_destructor(void *buf, void *arg) 247856567907SDavid Edmondson { 247956567907SDavid Edmondson _NOTE(ARGUNUSED(arg)); 248056567907SDavid Edmondson xnf_txbuf_t *txp = buf; 248156567907SDavid Edmondson 248256567907SDavid Edmondson ddi_dma_free_handle(&txp->tx_dma_handle); 2483843e1988Sjohnlev } 2484843e1988Sjohnlev 2485551bc2a6Smrj /* 2486551bc2a6Smrj * Statistics. 2487551bc2a6Smrj */ 2488551bc2a6Smrj static char *xnf_aux_statistics[] = { 2489551bc2a6Smrj "tx_cksum_deferred", 2490551bc2a6Smrj "rx_cksum_no_need", 2491551bc2a6Smrj "interrupts", 2492551bc2a6Smrj "unclaimed_interrupts", 2493551bc2a6Smrj "tx_pullup", 2494551bc2a6Smrj "tx_pagebndry", 2495551bc2a6Smrj "tx_attempt", 249656567907SDavid Edmondson "buf_allocated", 249756567907SDavid Edmondson "buf_outstanding", 249856567907SDavid Edmondson "gref_outstanding", 249956567907SDavid Edmondson "gref_failure", 250056567907SDavid Edmondson "gref_peak", 250156567907SDavid Edmondson "rx_allocb_fail", 250256567907SDavid Edmondson "rx_desballoc_fail", 2503551bc2a6Smrj }; 2504551bc2a6Smrj 2505551bc2a6Smrj static int 2506551bc2a6Smrj xnf_kstat_aux_update(kstat_t *ksp, int flag) 2507551bc2a6Smrj { 2508551bc2a6Smrj xnf_t *xnfp; 2509551bc2a6Smrj kstat_named_t *knp; 2510551bc2a6Smrj 2511551bc2a6Smrj if (flag != KSTAT_READ) 2512551bc2a6Smrj return (EACCES); 2513551bc2a6Smrj 2514551bc2a6Smrj xnfp = ksp->ks_private; 2515551bc2a6Smrj knp = ksp->ks_data; 2516551bc2a6Smrj 2517551bc2a6Smrj /* 2518551bc2a6Smrj * Assignment order must match that of the names in 2519551bc2a6Smrj * xnf_aux_statistics. 2520551bc2a6Smrj */ 2521551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_tx_cksum_deferred; 2522551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_rx_cksum_no_need; 2523551bc2a6Smrj 2524551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_interrupts; 2525551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_unclaimed_interrupts; 2526551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_tx_pullup; 2527551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_tx_pagebndry; 2528551bc2a6Smrj (knp++)->value.ui64 = xnfp->xnf_stat_tx_attempt; 2529551bc2a6Smrj 253056567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_buf_allocated; 253156567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_buf_outstanding; 253256567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_gref_outstanding; 253356567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_gref_failure; 253456567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_gref_peak; 253556567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_rx_allocb_fail; 253656567907SDavid Edmondson (knp++)->value.ui64 = xnfp->xnf_stat_rx_desballoc_fail; 2537551bc2a6Smrj 2538551bc2a6Smrj return (0); 2539551bc2a6Smrj } 2540551bc2a6Smrj 2541551bc2a6Smrj static boolean_t 2542551bc2a6Smrj xnf_kstat_init(xnf_t *xnfp) 2543551bc2a6Smrj { 2544551bc2a6Smrj int nstat = sizeof (xnf_aux_statistics) / 2545551bc2a6Smrj sizeof (xnf_aux_statistics[0]); 2546551bc2a6Smrj char **cp = xnf_aux_statistics; 2547551bc2a6Smrj kstat_named_t *knp; 2548551bc2a6Smrj 2549551bc2a6Smrj /* 2550551bc2a6Smrj * Create and initialise kstats. 2551551bc2a6Smrj */ 2552551bc2a6Smrj if ((xnfp->xnf_kstat_aux = kstat_create("xnf", 2553551bc2a6Smrj ddi_get_instance(xnfp->xnf_devinfo), 2554551bc2a6Smrj "aux_statistics", "net", KSTAT_TYPE_NAMED, 2555551bc2a6Smrj nstat, 0)) == NULL) 2556551bc2a6Smrj return (B_FALSE); 2557551bc2a6Smrj 2558551bc2a6Smrj xnfp->xnf_kstat_aux->ks_private = xnfp; 2559551bc2a6Smrj xnfp->xnf_kstat_aux->ks_update = xnf_kstat_aux_update; 2560551bc2a6Smrj 2561551bc2a6Smrj knp = xnfp->xnf_kstat_aux->ks_data; 2562551bc2a6Smrj while (nstat > 0) { 2563551bc2a6Smrj kstat_named_init(knp, *cp, KSTAT_DATA_UINT64); 2564551bc2a6Smrj 2565551bc2a6Smrj knp++; 2566551bc2a6Smrj cp++; 2567551bc2a6Smrj nstat--; 2568551bc2a6Smrj } 2569551bc2a6Smrj 2570551bc2a6Smrj kstat_install(xnfp->xnf_kstat_aux); 2571551bc2a6Smrj 2572551bc2a6Smrj return (B_TRUE); 2573551bc2a6Smrj } 2574551bc2a6Smrj 2575843e1988Sjohnlev static int 2576843e1988Sjohnlev xnf_stat(void *arg, uint_t stat, uint64_t *val) 2577843e1988Sjohnlev { 2578843e1988Sjohnlev xnf_t *xnfp = arg; 2579843e1988Sjohnlev 258056567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 2581551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 2582843e1988Sjohnlev 2583551bc2a6Smrj #define mac_stat(q, r) \ 2584843e1988Sjohnlev case (MAC_STAT_##q): \ 2585551bc2a6Smrj *val = xnfp->xnf_stat_##r; \ 2586551bc2a6Smrj break 2587551bc2a6Smrj 2588551bc2a6Smrj #define ether_stat(q, r) \ 2589551bc2a6Smrj case (ETHER_STAT_##q): \ 2590551bc2a6Smrj *val = xnfp->xnf_stat_##r; \ 2591843e1988Sjohnlev break 2592843e1988Sjohnlev 2593843e1988Sjohnlev switch (stat) { 2594843e1988Sjohnlev 2595551bc2a6Smrj mac_stat(IPACKETS, ipackets); 2596551bc2a6Smrj mac_stat(OPACKETS, opackets); 2597551bc2a6Smrj mac_stat(RBYTES, rbytes); 2598551bc2a6Smrj mac_stat(OBYTES, obytes); 2599551bc2a6Smrj mac_stat(NORCVBUF, norxbuf); 2600551bc2a6Smrj mac_stat(IERRORS, errrx); 2601551bc2a6Smrj mac_stat(NOXMTBUF, tx_defer); 2602551bc2a6Smrj 2603551bc2a6Smrj ether_stat(MACRCV_ERRORS, mac_rcv_error); 2604551bc2a6Smrj ether_stat(TOOSHORT_ERRORS, runt); 2605843e1988Sjohnlev 26064bae950fSMax zhen /* always claim to be in full duplex mode */ 26074bae950fSMax zhen case ETHER_STAT_LINK_DUPLEX: 26084bae950fSMax zhen *val = LINK_DUPLEX_FULL; 26094bae950fSMax zhen break; 26104bae950fSMax zhen 26114bae950fSMax zhen /* always claim to be at 1Gb/s link speed */ 26124bae950fSMax zhen case MAC_STAT_IFSPEED: 26134bae950fSMax zhen *val = 1000000000ull; 26144bae950fSMax zhen break; 26154bae950fSMax zhen 2616843e1988Sjohnlev default: 2617551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 261856567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 2619843e1988Sjohnlev 2620843e1988Sjohnlev return (ENOTSUP); 2621843e1988Sjohnlev } 2622843e1988Sjohnlev 2623551bc2a6Smrj #undef mac_stat 2624551bc2a6Smrj #undef ether_stat 2625843e1988Sjohnlev 2626551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 262756567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 2628843e1988Sjohnlev 2629843e1988Sjohnlev return (0); 2630843e1988Sjohnlev } 2631843e1988Sjohnlev 2632843e1988Sjohnlev static boolean_t 2633843e1988Sjohnlev xnf_getcapab(void *arg, mac_capab_t cap, void *cap_data) 2634843e1988Sjohnlev { 263556567907SDavid Edmondson _NOTE(ARGUNUSED(arg)); 2636843e1988Sjohnlev 2637843e1988Sjohnlev switch (cap) { 2638843e1988Sjohnlev case MAC_CAPAB_HCKSUM: { 2639843e1988Sjohnlev uint32_t *capab = cap_data; 2640843e1988Sjohnlev 2641568a765bSdme /* 2642a859da42SDavid Edmondson * Whilst the flag used to communicate with the IO 2643a859da42SDavid Edmondson * domain is called "NETTXF_csum_blank", the checksum 2644a859da42SDavid Edmondson * in the packet must contain the pseudo-header 2645a859da42SDavid Edmondson * checksum and not zero. 2646568a765bSdme * 2647a859da42SDavid Edmondson * To help out the IO domain, we might use 2648a859da42SDavid Edmondson * HCKSUM_INET_PARTIAL. Unfortunately our stack will 2649a859da42SDavid Edmondson * then use checksum offload for IPv6 packets, which 2650a859da42SDavid Edmondson * the IO domain can't handle. 2651a859da42SDavid Edmondson * 2652a859da42SDavid Edmondson * As a result, we declare outselves capable of 2653a859da42SDavid Edmondson * HCKSUM_INET_FULL_V4. This means that we receive 2654a859da42SDavid Edmondson * IPv4 packets from the stack with a blank checksum 2655a859da42SDavid Edmondson * field and must insert the pseudo-header checksum 2656a859da42SDavid Edmondson * before passing the packet to the IO domain. 2657568a765bSdme */ 2658a859da42SDavid Edmondson *capab = HCKSUM_INET_FULL_V4; 2659843e1988Sjohnlev break; 2660843e1988Sjohnlev } 2661843e1988Sjohnlev default: 2662843e1988Sjohnlev return (B_FALSE); 2663843e1988Sjohnlev } 2664843e1988Sjohnlev 2665843e1988Sjohnlev return (B_TRUE); 2666843e1988Sjohnlev } 2667843e1988Sjohnlev 266856567907SDavid Edmondson /* 266956567907SDavid Edmondson * The state of the peer has changed - react accordingly. 267056567907SDavid Edmondson */ 2671843e1988Sjohnlev static void 2672843e1988Sjohnlev oe_state_change(dev_info_t *dip, ddi_eventcookie_t id, 2673843e1988Sjohnlev void *arg, void *impl_data) 2674843e1988Sjohnlev { 267556567907SDavid Edmondson _NOTE(ARGUNUSED(id, arg)); 2676843e1988Sjohnlev xnf_t *xnfp = ddi_get_driver_private(dip); 2677843e1988Sjohnlev XenbusState new_state = *(XenbusState *)impl_data; 2678843e1988Sjohnlev 2679843e1988Sjohnlev ASSERT(xnfp != NULL); 2680843e1988Sjohnlev 2681843e1988Sjohnlev switch (new_state) { 268256567907SDavid Edmondson case XenbusStateUnknown: 268356567907SDavid Edmondson case XenbusStateInitialising: 268456567907SDavid Edmondson case XenbusStateInitialised: 268556567907SDavid Edmondson case XenbusStateClosing: 268656567907SDavid Edmondson case XenbusStateClosed: 268756567907SDavid Edmondson case XenbusStateReconfiguring: 268856567907SDavid Edmondson case XenbusStateReconfigured: 268956567907SDavid Edmondson break; 269056567907SDavid Edmondson 269156567907SDavid Edmondson case XenbusStateInitWait: 269256567907SDavid Edmondson xnf_read_config(xnfp); 269356567907SDavid Edmondson 269456567907SDavid Edmondson if (!xnfp->xnf_be_rx_copy) { 269556567907SDavid Edmondson cmn_err(CE_WARN, 269656567907SDavid Edmondson "The xnf driver requires a dom0 that " 269756567907SDavid Edmondson "supports 'feature-rx-copy'."); 269856567907SDavid Edmondson (void) xvdi_switch_state(xnfp->xnf_devinfo, 269956567907SDavid Edmondson XBT_NULL, XenbusStateClosed); 270056567907SDavid Edmondson break; 270156567907SDavid Edmondson } 270256567907SDavid Edmondson 270356567907SDavid Edmondson /* 270456567907SDavid Edmondson * Connect to the backend. 270556567907SDavid Edmondson */ 270656567907SDavid Edmondson xnf_be_connect(xnfp); 270756567907SDavid Edmondson 270856567907SDavid Edmondson /* 270956567907SDavid Edmondson * Our MAC address as discovered by xnf_read_config(). 271056567907SDavid Edmondson */ 271156567907SDavid Edmondson mac_unicst_update(xnfp->xnf_mh, xnfp->xnf_mac_addr); 271256567907SDavid Edmondson 271356567907SDavid Edmondson break; 271456567907SDavid Edmondson 2715843e1988Sjohnlev case XenbusStateConnected: 271656567907SDavid Edmondson mutex_enter(&xnfp->xnf_rxlock); 2717551bc2a6Smrj mutex_enter(&xnfp->xnf_txlock); 2718843e1988Sjohnlev 2719551bc2a6Smrj xnfp->xnf_connected = B_TRUE; 2720a390c5f4Scz147101 /* 272156567907SDavid Edmondson * Wake up any threads waiting to send data to 272256567907SDavid Edmondson * backend. 2723a390c5f4Scz147101 */ 272456567907SDavid Edmondson cv_broadcast(&xnfp->xnf_cv_state); 2725843e1988Sjohnlev 2726551bc2a6Smrj mutex_exit(&xnfp->xnf_txlock); 272756567907SDavid Edmondson mutex_exit(&xnfp->xnf_rxlock); 2728843e1988Sjohnlev 2729a390c5f4Scz147101 /* 273056567907SDavid Edmondson * Kick the peer in case it missed any transmits 273156567907SDavid Edmondson * request in the TX ring. 2732a390c5f4Scz147101 */ 2733551bc2a6Smrj ec_notify_via_evtchn(xnfp->xnf_evtchn); 2734a390c5f4Scz147101 2735a390c5f4Scz147101 /* 273656567907SDavid Edmondson * There may already be completed receive requests in 273756567907SDavid Edmondson * the ring sent by backend after it gets connected 273856567907SDavid Edmondson * but before we see its state change here, so we call 273956567907SDavid Edmondson * xnf_intr() to handle them, if any. 2740a390c5f4Scz147101 */ 2741a390c5f4Scz147101 (void) xnf_intr((caddr_t)xnfp); 2742a390c5f4Scz147101 274356567907SDavid Edmondson /* 274456567907SDavid Edmondson * Mark the link up now that we are connected. 274556567907SDavid Edmondson */ 27464bae950fSMax zhen mac_link_update(xnfp->xnf_mh, LINK_STATE_UP); 27474bae950fSMax zhen 274856567907SDavid Edmondson /* 274956567907SDavid Edmondson * Tell the backend about the multicast addresses in 275056567907SDavid Edmondson * which we are interested. 275156567907SDavid Edmondson */ 275256567907SDavid Edmondson mac_multicast_refresh(xnfp->xnf_mh, NULL, xnfp, B_TRUE); 275356567907SDavid Edmondson 2754843e1988Sjohnlev break; 2755843e1988Sjohnlev 2756843e1988Sjohnlev default: 2757843e1988Sjohnlev break; 2758843e1988Sjohnlev } 2759843e1988Sjohnlev } 2760