1*7bd3a2e2SSriharsha Basavapatna /* 2*7bd3a2e2SSriharsha Basavapatna * CDDL HEADER START 3*7bd3a2e2SSriharsha Basavapatna * 4*7bd3a2e2SSriharsha Basavapatna * The contents of this file are subject to the terms of the 5*7bd3a2e2SSriharsha Basavapatna * Common Development and Distribution License (the "License"). 6*7bd3a2e2SSriharsha Basavapatna * You may not use this file except in compliance with the License. 7*7bd3a2e2SSriharsha Basavapatna * 8*7bd3a2e2SSriharsha Basavapatna * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7bd3a2e2SSriharsha Basavapatna * or http://www.opensolaris.org/os/licensing. 10*7bd3a2e2SSriharsha Basavapatna * See the License for the specific language governing permissions 11*7bd3a2e2SSriharsha Basavapatna * and limitations under the License. 12*7bd3a2e2SSriharsha Basavapatna * 13*7bd3a2e2SSriharsha Basavapatna * When distributing Covered Code, include this CDDL HEADER in each 14*7bd3a2e2SSriharsha Basavapatna * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7bd3a2e2SSriharsha Basavapatna * If applicable, add the following below this CDDL HEADER, with the 16*7bd3a2e2SSriharsha Basavapatna * fields enclosed by brackets "[]" replaced with your own identifying 17*7bd3a2e2SSriharsha Basavapatna * information: Portions Copyright [yyyy] [name of copyright owner] 18*7bd3a2e2SSriharsha Basavapatna * 19*7bd3a2e2SSriharsha Basavapatna * CDDL HEADER END 20*7bd3a2e2SSriharsha Basavapatna */ 21*7bd3a2e2SSriharsha Basavapatna 22*7bd3a2e2SSriharsha Basavapatna /* 23*7bd3a2e2SSriharsha Basavapatna * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24*7bd3a2e2SSriharsha Basavapatna * Use is subject to license terms. 25*7bd3a2e2SSriharsha Basavapatna */ 26*7bd3a2e2SSriharsha Basavapatna #include <sys/types.h> 27*7bd3a2e2SSriharsha Basavapatna #include <sys/errno.h> 28*7bd3a2e2SSriharsha Basavapatna #include <sys/sysmacros.h> 29*7bd3a2e2SSriharsha Basavapatna #include <sys/param.h> 30*7bd3a2e2SSriharsha Basavapatna #include <sys/machsystm.h> 31*7bd3a2e2SSriharsha Basavapatna #include <sys/stream.h> 32*7bd3a2e2SSriharsha Basavapatna #include <sys/strsubr.h> 33*7bd3a2e2SSriharsha Basavapatna #include <sys/kmem.h> 34*7bd3a2e2SSriharsha Basavapatna #include <sys/strsun.h> 35*7bd3a2e2SSriharsha Basavapatna #include <sys/callb.h> 36*7bd3a2e2SSriharsha Basavapatna #include <sys/sdt.h> 37*7bd3a2e2SSriharsha Basavapatna #include <sys/mach_descrip.h> 38*7bd3a2e2SSriharsha Basavapatna #include <sys/mdeg.h> 39*7bd3a2e2SSriharsha Basavapatna #include <net/if.h> 40*7bd3a2e2SSriharsha Basavapatna #include <sys/vsw.h> 41*7bd3a2e2SSriharsha Basavapatna #include <sys/vio_mailbox.h> 42*7bd3a2e2SSriharsha Basavapatna #include <sys/vio_common.h> 43*7bd3a2e2SSriharsha Basavapatna #include <sys/vnet_common.h> 44*7bd3a2e2SSriharsha Basavapatna #include <sys/vnet_mailbox.h> 45*7bd3a2e2SSriharsha Basavapatna #include <sys/vio_util.h> 46*7bd3a2e2SSriharsha Basavapatna 47*7bd3a2e2SSriharsha Basavapatna /* 48*7bd3a2e2SSriharsha Basavapatna * This file contains the implementation of TxDring data transfer mode of VIO 49*7bd3a2e2SSriharsha Basavapatna * Protocol in vsw. The functions in this file are invoked from vsw_ldc.c 50*7bd3a2e2SSriharsha Basavapatna * after TxDring mode is negotiated with the peer during attribute phase of 51*7bd3a2e2SSriharsha Basavapatna * handshake. This file contains functions that setup the transmit and receive 52*7bd3a2e2SSriharsha Basavapatna * descriptor rings, and associated resources in TxDring mode. It also contains 53*7bd3a2e2SSriharsha Basavapatna * the transmit and receive data processing functions that are invoked in 54*7bd3a2e2SSriharsha Basavapatna * TxDring mode. 55*7bd3a2e2SSriharsha Basavapatna */ 56*7bd3a2e2SSriharsha Basavapatna 57*7bd3a2e2SSriharsha Basavapatna /* Functions exported to vsw_ldc.c */ 58*7bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *vsw_create_tx_dring_info(vsw_ldc_t *); 59*7bd3a2e2SSriharsha Basavapatna int vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp); 60*7bd3a2e2SSriharsha Basavapatna void vsw_destroy_tx_dring(vsw_ldc_t *ldcp); 61*7bd3a2e2SSriharsha Basavapatna dring_info_t *vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt); 62*7bd3a2e2SSriharsha Basavapatna void vsw_unmap_rx_dring(vsw_ldc_t *ldcp); 63*7bd3a2e2SSriharsha Basavapatna int vsw_dringsend(vsw_ldc_t *, mblk_t *); 64*7bd3a2e2SSriharsha Basavapatna void vsw_ldc_msg_worker(void *arg); 65*7bd3a2e2SSriharsha Basavapatna void vsw_stop_msg_thread(vsw_ldc_t *ldcp); 66*7bd3a2e2SSriharsha Basavapatna void vsw_process_dringdata(void *, void *); 67*7bd3a2e2SSriharsha Basavapatna int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t); 68*7bd3a2e2SSriharsha Basavapatna int vsw_reclaim_dring(dring_info_t *dp, int start); 69*7bd3a2e2SSriharsha Basavapatna int vsw_dring_find_free_desc(dring_info_t *, vsw_private_desc_t **, int *); 70*7bd3a2e2SSriharsha Basavapatna 71*7bd3a2e2SSriharsha Basavapatna /* Internal functions */ 72*7bd3a2e2SSriharsha Basavapatna static int vsw_init_multipools(vsw_ldc_t *ldcp, vsw_t *vswp); 73*7bd3a2e2SSriharsha Basavapatna static dring_info_t *vsw_create_tx_dring(vsw_ldc_t *); 74*7bd3a2e2SSriharsha Basavapatna 75*7bd3a2e2SSriharsha Basavapatna /* Functions imported from vsw_ldc.c */ 76*7bd3a2e2SSriharsha Basavapatna extern void vsw_process_pkt(void *); 77*7bd3a2e2SSriharsha Basavapatna extern void vsw_destroy_rxpools(void *); 78*7bd3a2e2SSriharsha Basavapatna extern dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp, 79*7bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *dring_pkt); 80*7bd3a2e2SSriharsha Basavapatna extern void vsw_process_conn_evt(vsw_ldc_t *, uint16_t); 81*7bd3a2e2SSriharsha Basavapatna extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 82*7bd3a2e2SSriharsha Basavapatna 83*7bd3a2e2SSriharsha Basavapatna /* Tunables */ 84*7bd3a2e2SSriharsha Basavapatna extern int vsw_wretries; 85*7bd3a2e2SSriharsha Basavapatna extern int vsw_recv_delay; 86*7bd3a2e2SSriharsha Basavapatna extern int vsw_recv_retries; 87*7bd3a2e2SSriharsha Basavapatna extern boolean_t vsw_jumbo_rxpools; 88*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_chain_len; 89*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_descriptors; 90*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size1; 91*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size2; 92*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size3; 93*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_mblk_size4; 94*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks1; 95*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks2; 96*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks3; 97*7bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_mblks4; 98*7bd3a2e2SSriharsha Basavapatna 99*7bd3a2e2SSriharsha Basavapatna #define VSW_NUM_VMPOOLS 3 /* number of vio mblk pools */ 100*7bd3a2e2SSriharsha Basavapatna 101*7bd3a2e2SSriharsha Basavapatna #define SND_DRING_NACK(ldcp, pkt) \ 102*7bd3a2e2SSriharsha Basavapatna pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \ 103*7bd3a2e2SSriharsha Basavapatna pkt->tag.vio_sid = ldcp->local_session; \ 104*7bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)pkt, \ 105*7bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_TRUE); 106*7bd3a2e2SSriharsha Basavapatna 107*7bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t * 108*7bd3a2e2SSriharsha Basavapatna vsw_create_tx_dring_info(vsw_ldc_t *ldcp) 109*7bd3a2e2SSriharsha Basavapatna { 110*7bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *mp; 111*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 112*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 113*7bd3a2e2SSriharsha Basavapatna 114*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s enter\n", __func__); 115*7bd3a2e2SSriharsha Basavapatna 116*7bd3a2e2SSriharsha Basavapatna /* 117*7bd3a2e2SSriharsha Basavapatna * If we can't create a dring, obviously no point sending 118*7bd3a2e2SSriharsha Basavapatna * a message. 119*7bd3a2e2SSriharsha Basavapatna */ 120*7bd3a2e2SSriharsha Basavapatna if ((dp = vsw_create_tx_dring(ldcp)) == NULL) 121*7bd3a2e2SSriharsha Basavapatna return (NULL); 122*7bd3a2e2SSriharsha Basavapatna 123*7bd3a2e2SSriharsha Basavapatna mp = kmem_zalloc(sizeof (vio_dring_reg_msg_t), KM_SLEEP); 124*7bd3a2e2SSriharsha Basavapatna 125*7bd3a2e2SSriharsha Basavapatna mp->tag.vio_msgtype = VIO_TYPE_CTRL; 126*7bd3a2e2SSriharsha Basavapatna mp->tag.vio_subtype = VIO_SUBTYPE_INFO; 127*7bd3a2e2SSriharsha Basavapatna mp->tag.vio_subtype_env = VIO_DRING_REG; 128*7bd3a2e2SSriharsha Basavapatna mp->tag.vio_sid = ldcp->local_session; 129*7bd3a2e2SSriharsha Basavapatna 130*7bd3a2e2SSriharsha Basavapatna /* payload */ 131*7bd3a2e2SSriharsha Basavapatna mp->num_descriptors = dp->num_descriptors; 132*7bd3a2e2SSriharsha Basavapatna mp->descriptor_size = dp->descriptor_size; 133*7bd3a2e2SSriharsha Basavapatna mp->options = dp->options; 134*7bd3a2e2SSriharsha Basavapatna mp->ncookies = dp->dring_ncookies; 135*7bd3a2e2SSriharsha Basavapatna bcopy(&dp->dring_cookie[0], &mp->cookie[0], sizeof (ldc_mem_cookie_t)); 136*7bd3a2e2SSriharsha Basavapatna 137*7bd3a2e2SSriharsha Basavapatna mp->dring_ident = 0; 138*7bd3a2e2SSriharsha Basavapatna 139*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s exit\n", __func__); 140*7bd3a2e2SSriharsha Basavapatna 141*7bd3a2e2SSriharsha Basavapatna return (mp); 142*7bd3a2e2SSriharsha Basavapatna } 143*7bd3a2e2SSriharsha Basavapatna 144*7bd3a2e2SSriharsha Basavapatna /* 145*7bd3a2e2SSriharsha Basavapatna * Allocate transmit resources for the channel. The resources consist of a 146*7bd3a2e2SSriharsha Basavapatna * transmit descriptor ring and an associated transmit buffer area. 147*7bd3a2e2SSriharsha Basavapatna */ 148*7bd3a2e2SSriharsha Basavapatna static dring_info_t * 149*7bd3a2e2SSriharsha Basavapatna vsw_create_tx_dring(vsw_ldc_t *ldcp) 150*7bd3a2e2SSriharsha Basavapatna { 151*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 152*7bd3a2e2SSriharsha Basavapatna ldc_mem_info_t minfo; 153*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 154*7bd3a2e2SSriharsha Basavapatna 155*7bd3a2e2SSriharsha Basavapatna dp = (dring_info_t *)kmem_zalloc(sizeof (dring_info_t), KM_SLEEP); 156*7bd3a2e2SSriharsha Basavapatna mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL); 157*7bd3a2e2SSriharsha Basavapatna mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL); 158*7bd3a2e2SSriharsha Basavapatna ldcp->lane_out.dringp = dp; 159*7bd3a2e2SSriharsha Basavapatna 160*7bd3a2e2SSriharsha Basavapatna /* create public section of ring */ 161*7bd3a2e2SSriharsha Basavapatna if ((ldc_mem_dring_create(vsw_num_descriptors, 162*7bd3a2e2SSriharsha Basavapatna sizeof (vnet_public_desc_t), &dp->dring_handle)) != 0) { 163*7bd3a2e2SSriharsha Basavapatna 164*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_create_tx_dring(%lld): ldc dring create " 165*7bd3a2e2SSriharsha Basavapatna "failed", ldcp->ldc_id); 166*7bd3a2e2SSriharsha Basavapatna goto fail; 167*7bd3a2e2SSriharsha Basavapatna } 168*7bd3a2e2SSriharsha Basavapatna ASSERT(dp->dring_handle != NULL); 169*7bd3a2e2SSriharsha Basavapatna 170*7bd3a2e2SSriharsha Basavapatna /* 171*7bd3a2e2SSriharsha Basavapatna * Get the base address of the public section of the ring. 172*7bd3a2e2SSriharsha Basavapatna */ 173*7bd3a2e2SSriharsha Basavapatna if ((ldc_mem_dring_info(dp->dring_handle, &minfo)) != 0) { 174*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_create_tx_dring(%lld): dring info failed\n", 175*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id); 176*7bd3a2e2SSriharsha Basavapatna goto fail; 177*7bd3a2e2SSriharsha Basavapatna } else { 178*7bd3a2e2SSriharsha Basavapatna ASSERT(minfo.vaddr != 0); 179*7bd3a2e2SSriharsha Basavapatna dp->pub_addr = minfo.vaddr; 180*7bd3a2e2SSriharsha Basavapatna } 181*7bd3a2e2SSriharsha Basavapatna 182*7bd3a2e2SSriharsha Basavapatna dp->num_descriptors = vsw_num_descriptors; 183*7bd3a2e2SSriharsha Basavapatna dp->descriptor_size = sizeof (vnet_public_desc_t); 184*7bd3a2e2SSriharsha Basavapatna dp->options = VIO_TX_DRING; 185*7bd3a2e2SSriharsha Basavapatna dp->dring_ncookies = 1; /* guaranteed by ldc */ 186*7bd3a2e2SSriharsha Basavapatna 187*7bd3a2e2SSriharsha Basavapatna /* 188*7bd3a2e2SSriharsha Basavapatna * create private portion of ring 189*7bd3a2e2SSriharsha Basavapatna */ 190*7bd3a2e2SSriharsha Basavapatna dp->priv_addr = (vsw_private_desc_t *)kmem_zalloc( 191*7bd3a2e2SSriharsha Basavapatna (sizeof (vsw_private_desc_t) * vsw_num_descriptors), KM_SLEEP); 192*7bd3a2e2SSriharsha Basavapatna 193*7bd3a2e2SSriharsha Basavapatna if (vsw_setup_tx_dring(ldcp, dp)) { 194*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: unable to setup ring", __func__); 195*7bd3a2e2SSriharsha Basavapatna goto fail; 196*7bd3a2e2SSriharsha Basavapatna } 197*7bd3a2e2SSriharsha Basavapatna 198*7bd3a2e2SSriharsha Basavapatna /* bind dring to the channel */ 199*7bd3a2e2SSriharsha Basavapatna if ((ldc_mem_dring_bind(ldcp->ldc_handle, dp->dring_handle, 200*7bd3a2e2SSriharsha Basavapatna LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW, 201*7bd3a2e2SSriharsha Basavapatna &dp->dring_cookie[0], &dp->dring_ncookies)) != 0) { 202*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_create_tx_dring: unable to bind to channel " 203*7bd3a2e2SSriharsha Basavapatna "%lld", ldcp->ldc_id); 204*7bd3a2e2SSriharsha Basavapatna goto fail; 205*7bd3a2e2SSriharsha Basavapatna } 206*7bd3a2e2SSriharsha Basavapatna 207*7bd3a2e2SSriharsha Basavapatna /* haven't used any descriptors yet */ 208*7bd3a2e2SSriharsha Basavapatna dp->end_idx = 0; 209*7bd3a2e2SSriharsha Basavapatna dp->last_ack_recv = -1; 210*7bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE; 211*7bd3a2e2SSriharsha Basavapatna 212*7bd3a2e2SSriharsha Basavapatna return (dp); 213*7bd3a2e2SSriharsha Basavapatna 214*7bd3a2e2SSriharsha Basavapatna fail: 215*7bd3a2e2SSriharsha Basavapatna vsw_destroy_tx_dring(ldcp); 216*7bd3a2e2SSriharsha Basavapatna return (NULL); 217*7bd3a2e2SSriharsha Basavapatna } 218*7bd3a2e2SSriharsha Basavapatna 219*7bd3a2e2SSriharsha Basavapatna /* 220*7bd3a2e2SSriharsha Basavapatna * Setup the descriptors in the tx dring. 221*7bd3a2e2SSriharsha Basavapatna * Returns 0 on success, 1 on failure. 222*7bd3a2e2SSriharsha Basavapatna */ 223*7bd3a2e2SSriharsha Basavapatna int 224*7bd3a2e2SSriharsha Basavapatna vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp) 225*7bd3a2e2SSriharsha Basavapatna { 226*7bd3a2e2SSriharsha Basavapatna vnet_public_desc_t *pub_addr = NULL; 227*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t *priv_addr = NULL; 228*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 229*7bd3a2e2SSriharsha Basavapatna uint64_t *tmpp; 230*7bd3a2e2SSriharsha Basavapatna uint64_t offset = 0; 231*7bd3a2e2SSriharsha Basavapatna uint32_t ncookies = 0; 232*7bd3a2e2SSriharsha Basavapatna static char *name = "vsw_setup_ring"; 233*7bd3a2e2SSriharsha Basavapatna int i, j, nc, rv; 234*7bd3a2e2SSriharsha Basavapatna size_t data_sz; 235*7bd3a2e2SSriharsha Basavapatna void *data_addr; 236*7bd3a2e2SSriharsha Basavapatna 237*7bd3a2e2SSriharsha Basavapatna priv_addr = dp->priv_addr; 238*7bd3a2e2SSriharsha Basavapatna pub_addr = dp->pub_addr; 239*7bd3a2e2SSriharsha Basavapatna 240*7bd3a2e2SSriharsha Basavapatna /* public section may be null but private should never be */ 241*7bd3a2e2SSriharsha Basavapatna ASSERT(priv_addr != NULL); 242*7bd3a2e2SSriharsha Basavapatna 243*7bd3a2e2SSriharsha Basavapatna /* 244*7bd3a2e2SSriharsha Basavapatna * Allocate the region of memory which will be used to hold 245*7bd3a2e2SSriharsha Basavapatna * the data the descriptors will refer to. 246*7bd3a2e2SSriharsha Basavapatna */ 247*7bd3a2e2SSriharsha Basavapatna data_sz = vswp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN; 248*7bd3a2e2SSriharsha Basavapatna 249*7bd3a2e2SSriharsha Basavapatna /* 250*7bd3a2e2SSriharsha Basavapatna * In order to ensure that the number of ldc cookies per descriptor is 251*7bd3a2e2SSriharsha Basavapatna * limited to be within the default MAX_COOKIES (2), we take the steps 252*7bd3a2e2SSriharsha Basavapatna * outlined below: 253*7bd3a2e2SSriharsha Basavapatna * 254*7bd3a2e2SSriharsha Basavapatna * Align the entire data buffer area to 8K and carve out per descriptor 255*7bd3a2e2SSriharsha Basavapatna * data buffers starting from this 8K aligned base address. 256*7bd3a2e2SSriharsha Basavapatna * 257*7bd3a2e2SSriharsha Basavapatna * We round up the mtu specified to be a multiple of 2K or 4K. 258*7bd3a2e2SSriharsha Basavapatna * For sizes up to 12K we round up the size to the next 2K. 259*7bd3a2e2SSriharsha Basavapatna * For sizes > 12K we round up to the next 4K (otherwise sizes such as 260*7bd3a2e2SSriharsha Basavapatna * 14K could end up needing 3 cookies, with the buffer spread across 261*7bd3a2e2SSriharsha Basavapatna * 3 8K pages: 8K+6K, 2K+8K+2K, 6K+8K, ...). 262*7bd3a2e2SSriharsha Basavapatna */ 263*7bd3a2e2SSriharsha Basavapatna if (data_sz <= VNET_12K) { 264*7bd3a2e2SSriharsha Basavapatna data_sz = VNET_ROUNDUP_2K(data_sz); 265*7bd3a2e2SSriharsha Basavapatna } else { 266*7bd3a2e2SSriharsha Basavapatna data_sz = VNET_ROUNDUP_4K(data_sz); 267*7bd3a2e2SSriharsha Basavapatna } 268*7bd3a2e2SSriharsha Basavapatna 269*7bd3a2e2SSriharsha Basavapatna dp->desc_data_sz = data_sz; 270*7bd3a2e2SSriharsha Basavapatna 271*7bd3a2e2SSriharsha Basavapatna /* allocate extra 8K bytes for alignment */ 272*7bd3a2e2SSriharsha Basavapatna dp->data_sz = (vsw_num_descriptors * data_sz) + VNET_8K; 273*7bd3a2e2SSriharsha Basavapatna data_addr = kmem_alloc(dp->data_sz, KM_SLEEP); 274*7bd3a2e2SSriharsha Basavapatna dp->data_addr = data_addr; 275*7bd3a2e2SSriharsha Basavapatna 276*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: allocated %lld bytes at 0x%llx\n", name, 277*7bd3a2e2SSriharsha Basavapatna dp->data_sz, dp->data_addr); 278*7bd3a2e2SSriharsha Basavapatna 279*7bd3a2e2SSriharsha Basavapatna /* align the starting address of the data area to 8K */ 280*7bd3a2e2SSriharsha Basavapatna data_addr = (void *)VNET_ROUNDUP_8K((uintptr_t)data_addr); 281*7bd3a2e2SSriharsha Basavapatna 282*7bd3a2e2SSriharsha Basavapatna tmpp = (uint64_t *)data_addr; 283*7bd3a2e2SSriharsha Basavapatna offset = dp->desc_data_sz/sizeof (tmpp); 284*7bd3a2e2SSriharsha Basavapatna 285*7bd3a2e2SSriharsha Basavapatna /* 286*7bd3a2e2SSriharsha Basavapatna * Initialise some of the private and public (if they exist) 287*7bd3a2e2SSriharsha Basavapatna * descriptor fields. 288*7bd3a2e2SSriharsha Basavapatna */ 289*7bd3a2e2SSriharsha Basavapatna for (i = 0; i < vsw_num_descriptors; i++) { 290*7bd3a2e2SSriharsha Basavapatna mutex_init(&priv_addr->dstate_lock, NULL, MUTEX_DRIVER, NULL); 291*7bd3a2e2SSriharsha Basavapatna 292*7bd3a2e2SSriharsha Basavapatna if ((ldc_mem_alloc_handle(ldcp->ldc_handle, 293*7bd3a2e2SSriharsha Basavapatna &priv_addr->memhandle)) != 0) { 294*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: alloc mem handle failed", name); 295*7bd3a2e2SSriharsha Basavapatna goto fail; 296*7bd3a2e2SSriharsha Basavapatna } 297*7bd3a2e2SSriharsha Basavapatna 298*7bd3a2e2SSriharsha Basavapatna priv_addr->datap = (void *)tmpp; 299*7bd3a2e2SSriharsha Basavapatna 300*7bd3a2e2SSriharsha Basavapatna rv = ldc_mem_bind_handle(priv_addr->memhandle, 301*7bd3a2e2SSriharsha Basavapatna (caddr_t)priv_addr->datap, dp->desc_data_sz, 302*7bd3a2e2SSriharsha Basavapatna LDC_SHADOW_MAP, LDC_MEM_R|LDC_MEM_W, 303*7bd3a2e2SSriharsha Basavapatna &(priv_addr->memcookie[0]), &ncookies); 304*7bd3a2e2SSriharsha Basavapatna if (rv != 0) { 305*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): ldc_mem_bind_handle failed " 306*7bd3a2e2SSriharsha Basavapatna "(rv %d)", name, ldcp->ldc_id, rv); 307*7bd3a2e2SSriharsha Basavapatna goto fail; 308*7bd3a2e2SSriharsha Basavapatna } 309*7bd3a2e2SSriharsha Basavapatna priv_addr->bound = 1; 310*7bd3a2e2SSriharsha Basavapatna 311*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: %d: memcookie 0 : addr 0x%llx : size 0x%llx", 312*7bd3a2e2SSriharsha Basavapatna name, i, priv_addr->memcookie[0].addr, 313*7bd3a2e2SSriharsha Basavapatna priv_addr->memcookie[0].size); 314*7bd3a2e2SSriharsha Basavapatna 315*7bd3a2e2SSriharsha Basavapatna if (ncookies >= (uint32_t)(VSW_MAX_COOKIES + 1)) { 316*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld) ldc_mem_bind_handle returned " 317*7bd3a2e2SSriharsha Basavapatna "invalid num of cookies (%d) for size 0x%llx", 318*7bd3a2e2SSriharsha Basavapatna name, ldcp->ldc_id, ncookies, VSW_RING_EL_DATA_SZ); 319*7bd3a2e2SSriharsha Basavapatna 320*7bd3a2e2SSriharsha Basavapatna goto fail; 321*7bd3a2e2SSriharsha Basavapatna } else { 322*7bd3a2e2SSriharsha Basavapatna for (j = 1; j < ncookies; j++) { 323*7bd3a2e2SSriharsha Basavapatna rv = ldc_mem_nextcookie(priv_addr->memhandle, 324*7bd3a2e2SSriharsha Basavapatna &(priv_addr->memcookie[j])); 325*7bd3a2e2SSriharsha Basavapatna if (rv != 0) { 326*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: ldc_mem_nextcookie " 327*7bd3a2e2SSriharsha Basavapatna "failed rv (%d)", name, rv); 328*7bd3a2e2SSriharsha Basavapatna goto fail; 329*7bd3a2e2SSriharsha Basavapatna } 330*7bd3a2e2SSriharsha Basavapatna D3(vswp, "%s: memcookie %d : addr 0x%llx : " 331*7bd3a2e2SSriharsha Basavapatna "size 0x%llx", name, j, 332*7bd3a2e2SSriharsha Basavapatna priv_addr->memcookie[j].addr, 333*7bd3a2e2SSriharsha Basavapatna priv_addr->memcookie[j].size); 334*7bd3a2e2SSriharsha Basavapatna } 335*7bd3a2e2SSriharsha Basavapatna 336*7bd3a2e2SSriharsha Basavapatna } 337*7bd3a2e2SSriharsha Basavapatna priv_addr->ncookies = ncookies; 338*7bd3a2e2SSriharsha Basavapatna priv_addr->dstate = VIO_DESC_FREE; 339*7bd3a2e2SSriharsha Basavapatna 340*7bd3a2e2SSriharsha Basavapatna if (pub_addr != NULL) { 341*7bd3a2e2SSriharsha Basavapatna 342*7bd3a2e2SSriharsha Basavapatna /* link pub and private sides */ 343*7bd3a2e2SSriharsha Basavapatna priv_addr->descp = pub_addr; 344*7bd3a2e2SSriharsha Basavapatna 345*7bd3a2e2SSriharsha Basavapatna pub_addr->ncookies = priv_addr->ncookies; 346*7bd3a2e2SSriharsha Basavapatna 347*7bd3a2e2SSriharsha Basavapatna for (nc = 0; nc < pub_addr->ncookies; nc++) { 348*7bd3a2e2SSriharsha Basavapatna bcopy(&priv_addr->memcookie[nc], 349*7bd3a2e2SSriharsha Basavapatna &pub_addr->memcookie[nc], 350*7bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 351*7bd3a2e2SSriharsha Basavapatna } 352*7bd3a2e2SSriharsha Basavapatna 353*7bd3a2e2SSriharsha Basavapatna pub_addr->hdr.dstate = VIO_DESC_FREE; 354*7bd3a2e2SSriharsha Basavapatna pub_addr++; 355*7bd3a2e2SSriharsha Basavapatna } 356*7bd3a2e2SSriharsha Basavapatna 357*7bd3a2e2SSriharsha Basavapatna /* 358*7bd3a2e2SSriharsha Basavapatna * move to next element in the dring and the next 359*7bd3a2e2SSriharsha Basavapatna * position in the data buffer. 360*7bd3a2e2SSriharsha Basavapatna */ 361*7bd3a2e2SSriharsha Basavapatna priv_addr++; 362*7bd3a2e2SSriharsha Basavapatna tmpp += offset; 363*7bd3a2e2SSriharsha Basavapatna } 364*7bd3a2e2SSriharsha Basavapatna 365*7bd3a2e2SSriharsha Basavapatna return (0); 366*7bd3a2e2SSriharsha Basavapatna 367*7bd3a2e2SSriharsha Basavapatna fail: 368*7bd3a2e2SSriharsha Basavapatna /* return failure; caller will cleanup */ 369*7bd3a2e2SSriharsha Basavapatna return (1); 370*7bd3a2e2SSriharsha Basavapatna } 371*7bd3a2e2SSriharsha Basavapatna 372*7bd3a2e2SSriharsha Basavapatna /* 373*7bd3a2e2SSriharsha Basavapatna * Free transmit resources for the channel. 374*7bd3a2e2SSriharsha Basavapatna */ 375*7bd3a2e2SSriharsha Basavapatna void 376*7bd3a2e2SSriharsha Basavapatna vsw_destroy_tx_dring(vsw_ldc_t *ldcp) 377*7bd3a2e2SSriharsha Basavapatna { 378*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t *paddr = NULL; 379*7bd3a2e2SSriharsha Basavapatna int i; 380*7bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 381*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 382*7bd3a2e2SSriharsha Basavapatna 383*7bd3a2e2SSriharsha Basavapatna dp = lp->dringp; 384*7bd3a2e2SSriharsha Basavapatna if (dp == NULL) { 385*7bd3a2e2SSriharsha Basavapatna return; 386*7bd3a2e2SSriharsha Basavapatna } 387*7bd3a2e2SSriharsha Basavapatna 388*7bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->dlock); 389*7bd3a2e2SSriharsha Basavapatna 390*7bd3a2e2SSriharsha Basavapatna if (dp->priv_addr != NULL) { 391*7bd3a2e2SSriharsha Basavapatna /* 392*7bd3a2e2SSriharsha Basavapatna * First unbind and free the memory handles 393*7bd3a2e2SSriharsha Basavapatna * stored in each descriptor within the ring. 394*7bd3a2e2SSriharsha Basavapatna */ 395*7bd3a2e2SSriharsha Basavapatna for (i = 0; i < vsw_num_descriptors; i++) { 396*7bd3a2e2SSriharsha Basavapatna paddr = (vsw_private_desc_t *)dp->priv_addr + i; 397*7bd3a2e2SSriharsha Basavapatna if (paddr->memhandle != NULL) { 398*7bd3a2e2SSriharsha Basavapatna if (paddr->bound == 1) { 399*7bd3a2e2SSriharsha Basavapatna if (ldc_mem_unbind_handle( 400*7bd3a2e2SSriharsha Basavapatna paddr->memhandle) != 0) { 401*7bd3a2e2SSriharsha Basavapatna DERR(NULL, "error " 402*7bd3a2e2SSriharsha Basavapatna "unbinding handle for " 403*7bd3a2e2SSriharsha Basavapatna "ring 0x%llx at pos %d", 404*7bd3a2e2SSriharsha Basavapatna dp, i); 405*7bd3a2e2SSriharsha Basavapatna continue; 406*7bd3a2e2SSriharsha Basavapatna } 407*7bd3a2e2SSriharsha Basavapatna paddr->bound = 0; 408*7bd3a2e2SSriharsha Basavapatna } 409*7bd3a2e2SSriharsha Basavapatna 410*7bd3a2e2SSriharsha Basavapatna if (ldc_mem_free_handle( 411*7bd3a2e2SSriharsha Basavapatna paddr->memhandle) != 0) { 412*7bd3a2e2SSriharsha Basavapatna DERR(NULL, "error freeing " 413*7bd3a2e2SSriharsha Basavapatna "handle for ring 0x%llx " 414*7bd3a2e2SSriharsha Basavapatna "at pos %d", dp, i); 415*7bd3a2e2SSriharsha Basavapatna continue; 416*7bd3a2e2SSriharsha Basavapatna } 417*7bd3a2e2SSriharsha Basavapatna paddr->memhandle = NULL; 418*7bd3a2e2SSriharsha Basavapatna } 419*7bd3a2e2SSriharsha Basavapatna mutex_destroy(&paddr->dstate_lock); 420*7bd3a2e2SSriharsha Basavapatna } 421*7bd3a2e2SSriharsha Basavapatna kmem_free(dp->priv_addr, 422*7bd3a2e2SSriharsha Basavapatna (sizeof (vsw_private_desc_t) * vsw_num_descriptors)); 423*7bd3a2e2SSriharsha Basavapatna } 424*7bd3a2e2SSriharsha Basavapatna 425*7bd3a2e2SSriharsha Basavapatna /* 426*7bd3a2e2SSriharsha Basavapatna * Now unbind and destroy the ring itself. 427*7bd3a2e2SSriharsha Basavapatna */ 428*7bd3a2e2SSriharsha Basavapatna if (dp->dring_handle != NULL) { 429*7bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unbind(dp->dring_handle); 430*7bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_destroy(dp->dring_handle); 431*7bd3a2e2SSriharsha Basavapatna } 432*7bd3a2e2SSriharsha Basavapatna 433*7bd3a2e2SSriharsha Basavapatna if (dp->data_addr != NULL) { 434*7bd3a2e2SSriharsha Basavapatna kmem_free(dp->data_addr, dp->data_sz); 435*7bd3a2e2SSriharsha Basavapatna } 436*7bd3a2e2SSriharsha Basavapatna 437*7bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->dlock); 438*7bd3a2e2SSriharsha Basavapatna mutex_destroy(&dp->dlock); 439*7bd3a2e2SSriharsha Basavapatna mutex_destroy(&dp->restart_lock); 440*7bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (dring_info_t)); 441*7bd3a2e2SSriharsha Basavapatna lp->dringp = NULL; 442*7bd3a2e2SSriharsha Basavapatna } 443*7bd3a2e2SSriharsha Basavapatna 444*7bd3a2e2SSriharsha Basavapatna /* 445*7bd3a2e2SSriharsha Basavapatna * Map the transmit descriptor ring exported 446*7bd3a2e2SSriharsha Basavapatna * by the peer, as our receive descriptor ring. 447*7bd3a2e2SSriharsha Basavapatna */ 448*7bd3a2e2SSriharsha Basavapatna dring_info_t * 449*7bd3a2e2SSriharsha Basavapatna vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt) 450*7bd3a2e2SSriharsha Basavapatna { 451*7bd3a2e2SSriharsha Basavapatna int rv; 452*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 453*7bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *dring_pkt = pkt; 454*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 455*7bd3a2e2SSriharsha Basavapatna 456*7bd3a2e2SSriharsha Basavapatna dp = vsw_map_dring_cmn(ldcp, dring_pkt); 457*7bd3a2e2SSriharsha Basavapatna if (dp == NULL) { 458*7bd3a2e2SSriharsha Basavapatna return (NULL); 459*7bd3a2e2SSriharsha Basavapatna } 460*7bd3a2e2SSriharsha Basavapatna 461*7bd3a2e2SSriharsha Basavapatna /* TxDring mode specific initializations */ 462*7bd3a2e2SSriharsha Basavapatna dp->end_idx = 0; 463*7bd3a2e2SSriharsha Basavapatna ldcp->lane_in.dringp = dp; 464*7bd3a2e2SSriharsha Basavapatna 465*7bd3a2e2SSriharsha Basavapatna /* Allocate pools of receive mblks */ 466*7bd3a2e2SSriharsha Basavapatna rv = vsw_init_multipools(ldcp, vswp); 467*7bd3a2e2SSriharsha Basavapatna if (rv != 0) { 468*7bd3a2e2SSriharsha Basavapatna /* 469*7bd3a2e2SSriharsha Basavapatna * We do not return failure if receive mblk pools can't 470*7bd3a2e2SSriharsha Basavapatna * be allocated, instead allocb(9F) will be used to 471*7bd3a2e2SSriharsha Basavapatna * dynamically allocate buffers during receive. 472*7bd3a2e2SSriharsha Basavapatna */ 473*7bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s: unable to create free mblk pools for" 474*7bd3a2e2SSriharsha Basavapatna " channel %ld (rv %d)", __func__, ldcp->ldc_id, rv); 475*7bd3a2e2SSriharsha Basavapatna } 476*7bd3a2e2SSriharsha Basavapatna 477*7bd3a2e2SSriharsha Basavapatna return (dp); 478*7bd3a2e2SSriharsha Basavapatna } 479*7bd3a2e2SSriharsha Basavapatna 480*7bd3a2e2SSriharsha Basavapatna /* 481*7bd3a2e2SSriharsha Basavapatna * Unmap the receive descriptor ring. 482*7bd3a2e2SSriharsha Basavapatna */ 483*7bd3a2e2SSriharsha Basavapatna void 484*7bd3a2e2SSriharsha Basavapatna vsw_unmap_rx_dring(vsw_ldc_t *ldcp) 485*7bd3a2e2SSriharsha Basavapatna { 486*7bd3a2e2SSriharsha Basavapatna vio_mblk_pool_t *fvmp = NULL; 487*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 488*7bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_in; 489*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 490*7bd3a2e2SSriharsha Basavapatna 491*7bd3a2e2SSriharsha Basavapatna if ((dp = lp->dringp) == NULL) { 492*7bd3a2e2SSriharsha Basavapatna return; 493*7bd3a2e2SSriharsha Basavapatna } 494*7bd3a2e2SSriharsha Basavapatna 495*7bd3a2e2SSriharsha Basavapatna /* 496*7bd3a2e2SSriharsha Basavapatna * If we can't destroy all the rx pools for this channel, 497*7bd3a2e2SSriharsha Basavapatna * dispatch a task to retry and clean up those rx pools. Note 498*7bd3a2e2SSriharsha Basavapatna * that we don't need to wait for the task to complete. If the 499*7bd3a2e2SSriharsha Basavapatna * vsw device itself gets detached (vsw_detach()), it will wait 500*7bd3a2e2SSriharsha Basavapatna * for the task to complete implicitly in ddi_taskq_destroy(). 501*7bd3a2e2SSriharsha Basavapatna */ 502*7bd3a2e2SSriharsha Basavapatna vio_destroy_multipools(&ldcp->vmp, &fvmp); 503*7bd3a2e2SSriharsha Basavapatna if (fvmp != NULL) { 504*7bd3a2e2SSriharsha Basavapatna (void) ddi_taskq_dispatch(vswp->rxp_taskq, 505*7bd3a2e2SSriharsha Basavapatna vsw_destroy_rxpools, fvmp, DDI_SLEEP); 506*7bd3a2e2SSriharsha Basavapatna } 507*7bd3a2e2SSriharsha Basavapatna 508*7bd3a2e2SSriharsha Basavapatna if (dp->dring_handle != NULL) { 509*7bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unmap(dp->dring_handle); 510*7bd3a2e2SSriharsha Basavapatna } 511*7bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (dring_info_t)); 512*7bd3a2e2SSriharsha Basavapatna lp->dringp = NULL; 513*7bd3a2e2SSriharsha Basavapatna } 514*7bd3a2e2SSriharsha Basavapatna 515*7bd3a2e2SSriharsha Basavapatna static int 516*7bd3a2e2SSriharsha Basavapatna vsw_init_multipools(vsw_ldc_t *ldcp, vsw_t *vswp) 517*7bd3a2e2SSriharsha Basavapatna { 518*7bd3a2e2SSriharsha Basavapatna size_t data_sz; 519*7bd3a2e2SSriharsha Basavapatna int rv; 520*7bd3a2e2SSriharsha Basavapatna uint32_t sz1 = 0; 521*7bd3a2e2SSriharsha Basavapatna uint32_t sz2 = 0; 522*7bd3a2e2SSriharsha Basavapatna uint32_t sz3 = 0; 523*7bd3a2e2SSriharsha Basavapatna uint32_t sz4 = 0; 524*7bd3a2e2SSriharsha Basavapatna 525*7bd3a2e2SSriharsha Basavapatna /* 526*7bd3a2e2SSriharsha Basavapatna * We round up the mtu specified to be a multiple of 2K to limit the 527*7bd3a2e2SSriharsha Basavapatna * number of rx buffer pools created for a given mtu. 528*7bd3a2e2SSriharsha Basavapatna */ 529*7bd3a2e2SSriharsha Basavapatna data_sz = vswp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN; 530*7bd3a2e2SSriharsha Basavapatna data_sz = VNET_ROUNDUP_2K(data_sz); 531*7bd3a2e2SSriharsha Basavapatna 532*7bd3a2e2SSriharsha Basavapatna /* 533*7bd3a2e2SSriharsha Basavapatna * If pool sizes are specified, use them. Note that the presence of 534*7bd3a2e2SSriharsha Basavapatna * the first tunable will be used as a hint. 535*7bd3a2e2SSriharsha Basavapatna */ 536*7bd3a2e2SSriharsha Basavapatna if (vsw_mblk_size1 != 0) { 537*7bd3a2e2SSriharsha Basavapatna sz1 = vsw_mblk_size1; 538*7bd3a2e2SSriharsha Basavapatna sz2 = vsw_mblk_size2; 539*7bd3a2e2SSriharsha Basavapatna sz3 = vsw_mblk_size3; 540*7bd3a2e2SSriharsha Basavapatna sz4 = vsw_mblk_size4; 541*7bd3a2e2SSriharsha Basavapatna 542*7bd3a2e2SSriharsha Basavapatna if (sz4 == 0) { /* need 3 pools */ 543*7bd3a2e2SSriharsha Basavapatna 544*7bd3a2e2SSriharsha Basavapatna ldcp->max_rxpool_size = sz3; 545*7bd3a2e2SSriharsha Basavapatna rv = vio_init_multipools(&ldcp->vmp, 546*7bd3a2e2SSriharsha Basavapatna VSW_NUM_VMPOOLS, sz1, sz2, sz3, 547*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3); 548*7bd3a2e2SSriharsha Basavapatna 549*7bd3a2e2SSriharsha Basavapatna } else { 550*7bd3a2e2SSriharsha Basavapatna 551*7bd3a2e2SSriharsha Basavapatna ldcp->max_rxpool_size = sz4; 552*7bd3a2e2SSriharsha Basavapatna rv = vio_init_multipools(&ldcp->vmp, 553*7bd3a2e2SSriharsha Basavapatna VSW_NUM_VMPOOLS + 1, sz1, sz2, sz3, sz4, 554*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3, 555*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks4); 556*7bd3a2e2SSriharsha Basavapatna 557*7bd3a2e2SSriharsha Basavapatna } 558*7bd3a2e2SSriharsha Basavapatna 559*7bd3a2e2SSriharsha Basavapatna return (rv); 560*7bd3a2e2SSriharsha Basavapatna } 561*7bd3a2e2SSriharsha Basavapatna 562*7bd3a2e2SSriharsha Basavapatna /* 563*7bd3a2e2SSriharsha Basavapatna * Pool sizes are not specified. We select the pool sizes based on the 564*7bd3a2e2SSriharsha Basavapatna * mtu if vnet_jumbo_rxpools is enabled. 565*7bd3a2e2SSriharsha Basavapatna */ 566*7bd3a2e2SSriharsha Basavapatna if (vsw_jumbo_rxpools == B_FALSE || data_sz == VNET_2K) { 567*7bd3a2e2SSriharsha Basavapatna /* 568*7bd3a2e2SSriharsha Basavapatna * Receive buffer pool allocation based on mtu is disabled. 569*7bd3a2e2SSriharsha Basavapatna * Use the default mechanism of standard size pool allocation. 570*7bd3a2e2SSriharsha Basavapatna */ 571*7bd3a2e2SSriharsha Basavapatna sz1 = VSW_MBLK_SZ_128; 572*7bd3a2e2SSriharsha Basavapatna sz2 = VSW_MBLK_SZ_256; 573*7bd3a2e2SSriharsha Basavapatna sz3 = VSW_MBLK_SZ_2048; 574*7bd3a2e2SSriharsha Basavapatna ldcp->max_rxpool_size = sz3; 575*7bd3a2e2SSriharsha Basavapatna 576*7bd3a2e2SSriharsha Basavapatna rv = vio_init_multipools(&ldcp->vmp, VSW_NUM_VMPOOLS, 577*7bd3a2e2SSriharsha Basavapatna sz1, sz2, sz3, 578*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3); 579*7bd3a2e2SSriharsha Basavapatna 580*7bd3a2e2SSriharsha Basavapatna return (rv); 581*7bd3a2e2SSriharsha Basavapatna } 582*7bd3a2e2SSriharsha Basavapatna 583*7bd3a2e2SSriharsha Basavapatna switch (data_sz) { 584*7bd3a2e2SSriharsha Basavapatna 585*7bd3a2e2SSriharsha Basavapatna case VNET_4K: 586*7bd3a2e2SSriharsha Basavapatna 587*7bd3a2e2SSriharsha Basavapatna sz1 = VSW_MBLK_SZ_128; 588*7bd3a2e2SSriharsha Basavapatna sz2 = VSW_MBLK_SZ_256; 589*7bd3a2e2SSriharsha Basavapatna sz3 = VSW_MBLK_SZ_2048; 590*7bd3a2e2SSriharsha Basavapatna sz4 = sz3 << 1; /* 4K */ 591*7bd3a2e2SSriharsha Basavapatna ldcp->max_rxpool_size = sz4; 592*7bd3a2e2SSriharsha Basavapatna 593*7bd3a2e2SSriharsha Basavapatna rv = vio_init_multipools(&ldcp->vmp, VSW_NUM_VMPOOLS + 1, 594*7bd3a2e2SSriharsha Basavapatna sz1, sz2, sz3, sz4, 595*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3, 596*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks4); 597*7bd3a2e2SSriharsha Basavapatna break; 598*7bd3a2e2SSriharsha Basavapatna 599*7bd3a2e2SSriharsha Basavapatna default: /* data_sz: 4K+ to 16K */ 600*7bd3a2e2SSriharsha Basavapatna 601*7bd3a2e2SSriharsha Basavapatna sz1 = VSW_MBLK_SZ_256; 602*7bd3a2e2SSriharsha Basavapatna sz2 = VSW_MBLK_SZ_2048; 603*7bd3a2e2SSriharsha Basavapatna sz3 = data_sz >> 1; /* Jumbo-size/2 */ 604*7bd3a2e2SSriharsha Basavapatna sz4 = data_sz; /* Jumbo-size */ 605*7bd3a2e2SSriharsha Basavapatna ldcp->max_rxpool_size = sz4; 606*7bd3a2e2SSriharsha Basavapatna 607*7bd3a2e2SSriharsha Basavapatna rv = vio_init_multipools(&ldcp->vmp, VSW_NUM_VMPOOLS + 1, 608*7bd3a2e2SSriharsha Basavapatna sz1, sz2, sz3, sz4, 609*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks1, vsw_num_mblks2, vsw_num_mblks3, 610*7bd3a2e2SSriharsha Basavapatna vsw_num_mblks4); 611*7bd3a2e2SSriharsha Basavapatna break; 612*7bd3a2e2SSriharsha Basavapatna } 613*7bd3a2e2SSriharsha Basavapatna 614*7bd3a2e2SSriharsha Basavapatna return (rv); 615*7bd3a2e2SSriharsha Basavapatna 616*7bd3a2e2SSriharsha Basavapatna } 617*7bd3a2e2SSriharsha Basavapatna 618*7bd3a2e2SSriharsha Basavapatna /* 619*7bd3a2e2SSriharsha Basavapatna * Generic routine to send message out over ldc channel. 620*7bd3a2e2SSriharsha Basavapatna * 621*7bd3a2e2SSriharsha Basavapatna * It is possible that when we attempt to write over the ldc channel 622*7bd3a2e2SSriharsha Basavapatna * that we get notified that it has been reset. Depending on the value 623*7bd3a2e2SSriharsha Basavapatna * of the handle_reset flag we either handle that event here or simply 624*7bd3a2e2SSriharsha Basavapatna * notify the caller that the channel was reset. 625*7bd3a2e2SSriharsha Basavapatna */ 626*7bd3a2e2SSriharsha Basavapatna int 627*7bd3a2e2SSriharsha Basavapatna vsw_send_msg(vsw_ldc_t *ldcp, void *msgp, int size, boolean_t handle_reset) 628*7bd3a2e2SSriharsha Basavapatna { 629*7bd3a2e2SSriharsha Basavapatna int rv; 630*7bd3a2e2SSriharsha Basavapatna size_t msglen = size; 631*7bd3a2e2SSriharsha Basavapatna vio_msg_tag_t *tag = (vio_msg_tag_t *)msgp; 632*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 633*7bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *dmsg; 634*7bd3a2e2SSriharsha Basavapatna vio_raw_data_msg_t *rmsg; 635*7bd3a2e2SSriharsha Basavapatna vnet_ibnd_desc_t *imsg; 636*7bd3a2e2SSriharsha Basavapatna boolean_t data_msg = B_FALSE; 637*7bd3a2e2SSriharsha Basavapatna int retries = vsw_wretries; 638*7bd3a2e2SSriharsha Basavapatna 639*7bd3a2e2SSriharsha Basavapatna D1(vswp, "vsw_send_msg (%lld) enter : sending %d bytes", 640*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, size); 641*7bd3a2e2SSriharsha Basavapatna 642*7bd3a2e2SSriharsha Basavapatna D2(vswp, "send_msg: type 0x%llx", tag->vio_msgtype); 643*7bd3a2e2SSriharsha Basavapatna D2(vswp, "send_msg: stype 0x%llx", tag->vio_subtype); 644*7bd3a2e2SSriharsha Basavapatna D2(vswp, "send_msg: senv 0x%llx", tag->vio_subtype_env); 645*7bd3a2e2SSriharsha Basavapatna 646*7bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->ldc_txlock); 647*7bd3a2e2SSriharsha Basavapatna 648*7bd3a2e2SSriharsha Basavapatna if (tag->vio_subtype == VIO_SUBTYPE_INFO) { 649*7bd3a2e2SSriharsha Basavapatna if (tag->vio_subtype_env == VIO_DRING_DATA) { 650*7bd3a2e2SSriharsha Basavapatna dmsg = (vio_dring_msg_t *)tag; 651*7bd3a2e2SSriharsha Basavapatna dmsg->seq_num = ldcp->lane_out.seq_num; 652*7bd3a2e2SSriharsha Basavapatna data_msg = B_TRUE; 653*7bd3a2e2SSriharsha Basavapatna } else if (tag->vio_subtype_env == VIO_PKT_DATA) { 654*7bd3a2e2SSriharsha Basavapatna rmsg = (vio_raw_data_msg_t *)tag; 655*7bd3a2e2SSriharsha Basavapatna rmsg->seq_num = ldcp->lane_out.seq_num; 656*7bd3a2e2SSriharsha Basavapatna data_msg = B_TRUE; 657*7bd3a2e2SSriharsha Basavapatna } else if (tag->vio_subtype_env == VIO_DESC_DATA) { 658*7bd3a2e2SSriharsha Basavapatna imsg = (vnet_ibnd_desc_t *)tag; 659*7bd3a2e2SSriharsha Basavapatna imsg->hdr.seq_num = ldcp->lane_out.seq_num; 660*7bd3a2e2SSriharsha Basavapatna data_msg = B_TRUE; 661*7bd3a2e2SSriharsha Basavapatna } 662*7bd3a2e2SSriharsha Basavapatna } 663*7bd3a2e2SSriharsha Basavapatna 664*7bd3a2e2SSriharsha Basavapatna do { 665*7bd3a2e2SSriharsha Basavapatna msglen = size; 666*7bd3a2e2SSriharsha Basavapatna rv = ldc_write(ldcp->ldc_handle, (caddr_t)msgp, &msglen); 667*7bd3a2e2SSriharsha Basavapatna } while (rv == EWOULDBLOCK && --retries > 0); 668*7bd3a2e2SSriharsha Basavapatna 669*7bd3a2e2SSriharsha Basavapatna if (rv == 0 && data_msg == B_TRUE) { 670*7bd3a2e2SSriharsha Basavapatna ldcp->lane_out.seq_num++; 671*7bd3a2e2SSriharsha Basavapatna } 672*7bd3a2e2SSriharsha Basavapatna 673*7bd3a2e2SSriharsha Basavapatna if ((rv != 0) || (msglen != size)) { 674*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "vsw_send_msg:ldc_write failed: chan(%lld) rv(%d) " 675*7bd3a2e2SSriharsha Basavapatna "size (%d) msglen(%d)\n", ldcp->ldc_id, rv, size, msglen); 676*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.oerrors++; 677*7bd3a2e2SSriharsha Basavapatna } 678*7bd3a2e2SSriharsha Basavapatna 679*7bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->ldc_txlock); 680*7bd3a2e2SSriharsha Basavapatna 681*7bd3a2e2SSriharsha Basavapatna /* 682*7bd3a2e2SSriharsha Basavapatna * If channel has been reset we either handle it here or 683*7bd3a2e2SSriharsha Basavapatna * simply report back that it has been reset and let caller 684*7bd3a2e2SSriharsha Basavapatna * decide what to do. 685*7bd3a2e2SSriharsha Basavapatna */ 686*7bd3a2e2SSriharsha Basavapatna if (rv == ECONNRESET) { 687*7bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s (%lld) channel reset", __func__, ldcp->ldc_id); 688*7bd3a2e2SSriharsha Basavapatna 689*7bd3a2e2SSriharsha Basavapatna if (handle_reset) { 690*7bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 691*7bd3a2e2SSriharsha Basavapatna } 692*7bd3a2e2SSriharsha Basavapatna } 693*7bd3a2e2SSriharsha Basavapatna 694*7bd3a2e2SSriharsha Basavapatna return (rv); 695*7bd3a2e2SSriharsha Basavapatna } 696*7bd3a2e2SSriharsha Basavapatna 697*7bd3a2e2SSriharsha Basavapatna /* 698*7bd3a2e2SSriharsha Basavapatna * A per LDC worker thread to process ldc messages. This thread is woken up by 699*7bd3a2e2SSriharsha Basavapatna * the LDC interrupt handler to process LDC packets and receive data. 700*7bd3a2e2SSriharsha Basavapatna */ 701*7bd3a2e2SSriharsha Basavapatna void 702*7bd3a2e2SSriharsha Basavapatna vsw_ldc_msg_worker(void *arg) 703*7bd3a2e2SSriharsha Basavapatna { 704*7bd3a2e2SSriharsha Basavapatna callb_cpr_t cprinfo; 705*7bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 706*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 707*7bd3a2e2SSriharsha Basavapatna 708*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id); 709*7bd3a2e2SSriharsha Basavapatna CALLB_CPR_INIT(&cprinfo, &ldcp->msg_thr_lock, callb_generic_cpr, 710*7bd3a2e2SSriharsha Basavapatna "vsw_msg_thread"); 711*7bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->msg_thr_lock); 712*7bd3a2e2SSriharsha Basavapatna while (!(ldcp->msg_thr_flags & VSW_WTHR_STOP)) { 713*7bd3a2e2SSriharsha Basavapatna 714*7bd3a2e2SSriharsha Basavapatna CALLB_CPR_SAFE_BEGIN(&cprinfo); 715*7bd3a2e2SSriharsha Basavapatna /* 716*7bd3a2e2SSriharsha Basavapatna * Wait until the data is received or a stop 717*7bd3a2e2SSriharsha Basavapatna * request is received. 718*7bd3a2e2SSriharsha Basavapatna */ 719*7bd3a2e2SSriharsha Basavapatna while (!(ldcp->msg_thr_flags & 720*7bd3a2e2SSriharsha Basavapatna (VSW_WTHR_DATARCVD | VSW_WTHR_STOP))) { 721*7bd3a2e2SSriharsha Basavapatna cv_wait(&ldcp->msg_thr_cv, &ldcp->msg_thr_lock); 722*7bd3a2e2SSriharsha Basavapatna } 723*7bd3a2e2SSriharsha Basavapatna CALLB_CPR_SAFE_END(&cprinfo, &ldcp->msg_thr_lock) 724*7bd3a2e2SSriharsha Basavapatna 725*7bd3a2e2SSriharsha Basavapatna /* 726*7bd3a2e2SSriharsha Basavapatna * First process the stop request. 727*7bd3a2e2SSriharsha Basavapatna */ 728*7bd3a2e2SSriharsha Basavapatna if (ldcp->msg_thr_flags & VSW_WTHR_STOP) { 729*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld):Rx thread stopped\n", 730*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 731*7bd3a2e2SSriharsha Basavapatna break; 732*7bd3a2e2SSriharsha Basavapatna } 733*7bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags &= ~VSW_WTHR_DATARCVD; 734*7bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->msg_thr_lock); 735*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):calling vsw_process_pkt\n", 736*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 737*7bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->ldc_cblock); 738*7bd3a2e2SSriharsha Basavapatna vsw_process_pkt(ldcp); 739*7bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->ldc_cblock); 740*7bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->msg_thr_lock); 741*7bd3a2e2SSriharsha Basavapatna } 742*7bd3a2e2SSriharsha Basavapatna 743*7bd3a2e2SSriharsha Basavapatna /* 744*7bd3a2e2SSriharsha Basavapatna * Update the run status and wakeup the thread that 745*7bd3a2e2SSriharsha Basavapatna * has sent the stop request. 746*7bd3a2e2SSriharsha Basavapatna */ 747*7bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags &= ~VSW_WTHR_STOP; 748*7bd3a2e2SSriharsha Basavapatna ldcp->msg_thread = NULL; 749*7bd3a2e2SSriharsha Basavapatna CALLB_CPR_EXIT(&cprinfo); 750*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id); 751*7bd3a2e2SSriharsha Basavapatna thread_exit(); 752*7bd3a2e2SSriharsha Basavapatna } 753*7bd3a2e2SSriharsha Basavapatna 754*7bd3a2e2SSriharsha Basavapatna /* Co-ordinate with msg processing thread to stop it */ 755*7bd3a2e2SSriharsha Basavapatna void 756*7bd3a2e2SSriharsha Basavapatna vsw_stop_msg_thread(vsw_ldc_t *ldcp) 757*7bd3a2e2SSriharsha Basavapatna { 758*7bd3a2e2SSriharsha Basavapatna kt_did_t tid = 0; 759*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 760*7bd3a2e2SSriharsha Basavapatna 761*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id); 762*7bd3a2e2SSriharsha Basavapatna /* 763*7bd3a2e2SSriharsha Basavapatna * Send a stop request by setting the stop flag and 764*7bd3a2e2SSriharsha Basavapatna * wait until the msg process thread stops. 765*7bd3a2e2SSriharsha Basavapatna */ 766*7bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->msg_thr_lock); 767*7bd3a2e2SSriharsha Basavapatna if (ldcp->msg_thread != NULL) { 768*7bd3a2e2SSriharsha Basavapatna tid = ldcp->msg_thread->t_did; 769*7bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags |= VSW_WTHR_STOP; 770*7bd3a2e2SSriharsha Basavapatna cv_signal(&ldcp->msg_thr_cv); 771*7bd3a2e2SSriharsha Basavapatna } 772*7bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->msg_thr_lock); 773*7bd3a2e2SSriharsha Basavapatna 774*7bd3a2e2SSriharsha Basavapatna if (tid != 0) { 775*7bd3a2e2SSriharsha Basavapatna thread_join(tid); 776*7bd3a2e2SSriharsha Basavapatna } 777*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id); 778*7bd3a2e2SSriharsha Basavapatna } 779*7bd3a2e2SSriharsha Basavapatna 780*7bd3a2e2SSriharsha Basavapatna /* 781*7bd3a2e2SSriharsha Basavapatna * Send packet out via descriptor ring to a logical device. 782*7bd3a2e2SSriharsha Basavapatna */ 783*7bd3a2e2SSriharsha Basavapatna int 784*7bd3a2e2SSriharsha Basavapatna vsw_dringsend(vsw_ldc_t *ldcp, mblk_t *mp) 785*7bd3a2e2SSriharsha Basavapatna { 786*7bd3a2e2SSriharsha Basavapatna vio_dring_msg_t dring_pkt; 787*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp = NULL; 788*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t *priv_desc = NULL; 789*7bd3a2e2SSriharsha Basavapatna vnet_public_desc_t *pub = NULL; 790*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 791*7bd3a2e2SSriharsha Basavapatna mblk_t *bp; 792*7bd3a2e2SSriharsha Basavapatna size_t n, size; 793*7bd3a2e2SSriharsha Basavapatna caddr_t bufp; 794*7bd3a2e2SSriharsha Basavapatna int idx; 795*7bd3a2e2SSriharsha Basavapatna int status = LDC_TX_SUCCESS; 796*7bd3a2e2SSriharsha Basavapatna struct ether_header *ehp = (struct ether_header *)mp->b_rptr; 797*7bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 798*7bd3a2e2SSriharsha Basavapatna 799*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): enter\n", __func__, ldcp->ldc_id); 800*7bd3a2e2SSriharsha Basavapatna 801*7bd3a2e2SSriharsha Basavapatna /* TODO: make test a macro */ 802*7bd3a2e2SSriharsha Basavapatna if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) || 803*7bd3a2e2SSriharsha Basavapatna (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) { 804*7bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping " 805*7bd3a2e2SSriharsha Basavapatna "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status, 806*7bd3a2e2SSriharsha Basavapatna ldcp->lane_out.lstate); 807*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.oerrors++; 808*7bd3a2e2SSriharsha Basavapatna return (LDC_TX_FAILURE); 809*7bd3a2e2SSriharsha Basavapatna } 810*7bd3a2e2SSriharsha Basavapatna 811*7bd3a2e2SSriharsha Basavapatna if ((dp = ldcp->lane_out.dringp) == NULL) { 812*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): no dring for outbound lane on" 813*7bd3a2e2SSriharsha Basavapatna " channel %d", __func__, ldcp->ldc_id, ldcp->ldc_id); 814*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.oerrors++; 815*7bd3a2e2SSriharsha Basavapatna return (LDC_TX_FAILURE); 816*7bd3a2e2SSriharsha Basavapatna } 817*7bd3a2e2SSriharsha Basavapatna 818*7bd3a2e2SSriharsha Basavapatna size = msgsize(mp); 819*7bd3a2e2SSriharsha Basavapatna if (size > (size_t)lp->mtu) { 820*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__, 821*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, size); 822*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.oerrors++; 823*7bd3a2e2SSriharsha Basavapatna return (LDC_TX_FAILURE); 824*7bd3a2e2SSriharsha Basavapatna } 825*7bd3a2e2SSriharsha Basavapatna 826*7bd3a2e2SSriharsha Basavapatna /* 827*7bd3a2e2SSriharsha Basavapatna * Find a free descriptor 828*7bd3a2e2SSriharsha Basavapatna * 829*7bd3a2e2SSriharsha Basavapatna * Note: for the moment we are assuming that we will only 830*7bd3a2e2SSriharsha Basavapatna * have one dring going from the switch to each of its 831*7bd3a2e2SSriharsha Basavapatna * peers. This may change in the future. 832*7bd3a2e2SSriharsha Basavapatna */ 833*7bd3a2e2SSriharsha Basavapatna if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) { 834*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): no descriptor available for ring " 835*7bd3a2e2SSriharsha Basavapatna "at 0x%llx", __func__, ldcp->ldc_id, dp); 836*7bd3a2e2SSriharsha Basavapatna 837*7bd3a2e2SSriharsha Basavapatna /* nothing more we can do */ 838*7bd3a2e2SSriharsha Basavapatna status = LDC_TX_NORESOURCES; 839*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.tx_no_desc++; 840*7bd3a2e2SSriharsha Basavapatna goto vsw_dringsend_free_exit; 841*7bd3a2e2SSriharsha Basavapatna } else { 842*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): free private descriptor found at pos %ld " 843*7bd3a2e2SSriharsha Basavapatna "addr 0x%llx\n", __func__, ldcp->ldc_id, idx, priv_desc); 844*7bd3a2e2SSriharsha Basavapatna } 845*7bd3a2e2SSriharsha Basavapatna 846*7bd3a2e2SSriharsha Basavapatna /* copy data into the descriptor */ 847*7bd3a2e2SSriharsha Basavapatna bufp = priv_desc->datap; 848*7bd3a2e2SSriharsha Basavapatna bufp += VNET_IPALIGN; 849*7bd3a2e2SSriharsha Basavapatna for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) { 850*7bd3a2e2SSriharsha Basavapatna n = MBLKL(bp); 851*7bd3a2e2SSriharsha Basavapatna bcopy(bp->b_rptr, bufp, n); 852*7bd3a2e2SSriharsha Basavapatna bufp += n; 853*7bd3a2e2SSriharsha Basavapatna } 854*7bd3a2e2SSriharsha Basavapatna 855*7bd3a2e2SSriharsha Basavapatna priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size; 856*7bd3a2e2SSriharsha Basavapatna 857*7bd3a2e2SSriharsha Basavapatna pub = priv_desc->descp; 858*7bd3a2e2SSriharsha Basavapatna pub->nbytes = priv_desc->datalen; 859*7bd3a2e2SSriharsha Basavapatna 860*7bd3a2e2SSriharsha Basavapatna /* update statistics */ 861*7bd3a2e2SSriharsha Basavapatna if (IS_BROADCAST(ehp)) 862*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.brdcstxmt++; 863*7bd3a2e2SSriharsha Basavapatna else if (IS_MULTICAST(ehp)) 864*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.multixmt++; 865*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.opackets++; 866*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.obytes += priv_desc->datalen; 867*7bd3a2e2SSriharsha Basavapatna 868*7bd3a2e2SSriharsha Basavapatna mutex_enter(&priv_desc->dstate_lock); 869*7bd3a2e2SSriharsha Basavapatna pub->hdr.dstate = VIO_DESC_READY; 870*7bd3a2e2SSriharsha Basavapatna mutex_exit(&priv_desc->dstate_lock); 871*7bd3a2e2SSriharsha Basavapatna 872*7bd3a2e2SSriharsha Basavapatna /* 873*7bd3a2e2SSriharsha Basavapatna * Determine whether or not we need to send a message to our 874*7bd3a2e2SSriharsha Basavapatna * peer prompting them to read our newly updated descriptor(s). 875*7bd3a2e2SSriharsha Basavapatna */ 876*7bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->restart_lock); 877*7bd3a2e2SSriharsha Basavapatna if (dp->restart_reqd) { 878*7bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_FALSE; 879*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_data_msgs_sent++; 880*7bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 881*7bd3a2e2SSriharsha Basavapatna 882*7bd3a2e2SSriharsha Basavapatna /* 883*7bd3a2e2SSriharsha Basavapatna * Send a vio_dring_msg to peer to prompt them to read 884*7bd3a2e2SSriharsha Basavapatna * the updated descriptor ring. 885*7bd3a2e2SSriharsha Basavapatna */ 886*7bd3a2e2SSriharsha Basavapatna dring_pkt.tag.vio_msgtype = VIO_TYPE_DATA; 887*7bd3a2e2SSriharsha Basavapatna dring_pkt.tag.vio_subtype = VIO_SUBTYPE_INFO; 888*7bd3a2e2SSriharsha Basavapatna dring_pkt.tag.vio_subtype_env = VIO_DRING_DATA; 889*7bd3a2e2SSriharsha Basavapatna dring_pkt.tag.vio_sid = ldcp->local_session; 890*7bd3a2e2SSriharsha Basavapatna 891*7bd3a2e2SSriharsha Basavapatna /* Note - for now using first ring */ 892*7bd3a2e2SSriharsha Basavapatna dring_pkt.dring_ident = dp->ident; 893*7bd3a2e2SSriharsha Basavapatna 894*7bd3a2e2SSriharsha Basavapatna /* 895*7bd3a2e2SSriharsha Basavapatna * If last_ack_recv is -1 then we know we've not 896*7bd3a2e2SSriharsha Basavapatna * received any ack's yet, so this must be the first 897*7bd3a2e2SSriharsha Basavapatna * msg sent, so set the start to the begining of the ring. 898*7bd3a2e2SSriharsha Basavapatna */ 899*7bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->dlock); 900*7bd3a2e2SSriharsha Basavapatna if (dp->last_ack_recv == -1) { 901*7bd3a2e2SSriharsha Basavapatna dring_pkt.start_idx = 0; 902*7bd3a2e2SSriharsha Basavapatna } else { 903*7bd3a2e2SSriharsha Basavapatna dring_pkt.start_idx = 904*7bd3a2e2SSriharsha Basavapatna (dp->last_ack_recv + 1) % dp->num_descriptors; 905*7bd3a2e2SSriharsha Basavapatna } 906*7bd3a2e2SSriharsha Basavapatna dring_pkt.end_idx = -1; 907*7bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->dlock); 908*7bd3a2e2SSriharsha Basavapatna 909*7bd3a2e2SSriharsha Basavapatna D3(vswp, "%s(%lld): dring 0x%llx : ident 0x%llx\n", __func__, 910*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, dp, dring_pkt.dring_ident); 911*7bd3a2e2SSriharsha Basavapatna D3(vswp, "%s(%lld): start %lld : end %lld :\n", 912*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, dring_pkt.start_idx, 913*7bd3a2e2SSriharsha Basavapatna dring_pkt.end_idx); 914*7bd3a2e2SSriharsha Basavapatna 915*7bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)&dring_pkt, 916*7bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_TRUE); 917*7bd3a2e2SSriharsha Basavapatna 918*7bd3a2e2SSriharsha Basavapatna return (status); 919*7bd3a2e2SSriharsha Basavapatna 920*7bd3a2e2SSriharsha Basavapatna } else { 921*7bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 922*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): updating descp %d", __func__, 923*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, idx); 924*7bd3a2e2SSriharsha Basavapatna } 925*7bd3a2e2SSriharsha Basavapatna 926*7bd3a2e2SSriharsha Basavapatna vsw_dringsend_free_exit: 927*7bd3a2e2SSriharsha Basavapatna 928*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id); 929*7bd3a2e2SSriharsha Basavapatna return (status); 930*7bd3a2e2SSriharsha Basavapatna } 931*7bd3a2e2SSriharsha Basavapatna 932*7bd3a2e2SSriharsha Basavapatna /* 933*7bd3a2e2SSriharsha Basavapatna * Searches the private section of a ring for a free descriptor, 934*7bd3a2e2SSriharsha Basavapatna * starting at the location of the last free descriptor found 935*7bd3a2e2SSriharsha Basavapatna * previously. 936*7bd3a2e2SSriharsha Basavapatna * 937*7bd3a2e2SSriharsha Basavapatna * Returns 0 if free descriptor is available, and updates state 938*7bd3a2e2SSriharsha Basavapatna * of private descriptor to VIO_DESC_READY, otherwise returns 1. 939*7bd3a2e2SSriharsha Basavapatna * 940*7bd3a2e2SSriharsha Basavapatna * FUTURE: might need to return contiguous range of descriptors 941*7bd3a2e2SSriharsha Basavapatna * as dring info msg assumes all will be contiguous. 942*7bd3a2e2SSriharsha Basavapatna */ 943*7bd3a2e2SSriharsha Basavapatna int 944*7bd3a2e2SSriharsha Basavapatna vsw_dring_find_free_desc(dring_info_t *dringp, 945*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t **priv_p, int *idx) 946*7bd3a2e2SSriharsha Basavapatna { 947*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t *addr = NULL; 948*7bd3a2e2SSriharsha Basavapatna int num = vsw_num_descriptors; 949*7bd3a2e2SSriharsha Basavapatna int ret = 1; 950*7bd3a2e2SSriharsha Basavapatna 951*7bd3a2e2SSriharsha Basavapatna D1(NULL, "%s enter\n", __func__); 952*7bd3a2e2SSriharsha Basavapatna 953*7bd3a2e2SSriharsha Basavapatna ASSERT(dringp->priv_addr != NULL); 954*7bd3a2e2SSriharsha Basavapatna 955*7bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: searching ring, dringp 0x%llx : start pos %lld", 956*7bd3a2e2SSriharsha Basavapatna __func__, dringp, dringp->end_idx); 957*7bd3a2e2SSriharsha Basavapatna 958*7bd3a2e2SSriharsha Basavapatna addr = (vsw_private_desc_t *)dringp->priv_addr + dringp->end_idx; 959*7bd3a2e2SSriharsha Basavapatna 960*7bd3a2e2SSriharsha Basavapatna mutex_enter(&addr->dstate_lock); 961*7bd3a2e2SSriharsha Basavapatna if (addr->dstate == VIO_DESC_FREE) { 962*7bd3a2e2SSriharsha Basavapatna addr->dstate = VIO_DESC_READY; 963*7bd3a2e2SSriharsha Basavapatna *priv_p = addr; 964*7bd3a2e2SSriharsha Basavapatna *idx = dringp->end_idx; 965*7bd3a2e2SSriharsha Basavapatna dringp->end_idx = (dringp->end_idx + 1) % num; 966*7bd3a2e2SSriharsha Basavapatna ret = 0; 967*7bd3a2e2SSriharsha Basavapatna 968*7bd3a2e2SSriharsha Basavapatna } 969*7bd3a2e2SSriharsha Basavapatna mutex_exit(&addr->dstate_lock); 970*7bd3a2e2SSriharsha Basavapatna 971*7bd3a2e2SSriharsha Basavapatna /* ring full */ 972*7bd3a2e2SSriharsha Basavapatna if (ret == 1) { 973*7bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: no desp free: started at %d", __func__, 974*7bd3a2e2SSriharsha Basavapatna dringp->end_idx); 975*7bd3a2e2SSriharsha Basavapatna } 976*7bd3a2e2SSriharsha Basavapatna 977*7bd3a2e2SSriharsha Basavapatna D1(NULL, "%s: exit\n", __func__); 978*7bd3a2e2SSriharsha Basavapatna 979*7bd3a2e2SSriharsha Basavapatna return (ret); 980*7bd3a2e2SSriharsha Basavapatna } 981*7bd3a2e2SSriharsha Basavapatna 982*7bd3a2e2SSriharsha Basavapatna /* vsw_reclaim_dring -- reclaim descriptors */ 983*7bd3a2e2SSriharsha Basavapatna int 984*7bd3a2e2SSriharsha Basavapatna vsw_reclaim_dring(dring_info_t *dp, int start) 985*7bd3a2e2SSriharsha Basavapatna { 986*7bd3a2e2SSriharsha Basavapatna int i, j, len; 987*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t *priv_addr; 988*7bd3a2e2SSriharsha Basavapatna vnet_public_desc_t *pub_addr; 989*7bd3a2e2SSriharsha Basavapatna 990*7bd3a2e2SSriharsha Basavapatna pub_addr = (vnet_public_desc_t *)dp->pub_addr; 991*7bd3a2e2SSriharsha Basavapatna priv_addr = (vsw_private_desc_t *)dp->priv_addr; 992*7bd3a2e2SSriharsha Basavapatna len = dp->num_descriptors; 993*7bd3a2e2SSriharsha Basavapatna 994*7bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: start index %ld\n", __func__, start); 995*7bd3a2e2SSriharsha Basavapatna 996*7bd3a2e2SSriharsha Basavapatna j = 0; 997*7bd3a2e2SSriharsha Basavapatna for (i = start; j < len; i = (i + 1) % len, j++) { 998*7bd3a2e2SSriharsha Basavapatna pub_addr = (vnet_public_desc_t *)dp->pub_addr + i; 999*7bd3a2e2SSriharsha Basavapatna priv_addr = (vsw_private_desc_t *)dp->priv_addr + i; 1000*7bd3a2e2SSriharsha Basavapatna 1001*7bd3a2e2SSriharsha Basavapatna mutex_enter(&priv_addr->dstate_lock); 1002*7bd3a2e2SSriharsha Basavapatna if (pub_addr->hdr.dstate != VIO_DESC_DONE) { 1003*7bd3a2e2SSriharsha Basavapatna mutex_exit(&priv_addr->dstate_lock); 1004*7bd3a2e2SSriharsha Basavapatna break; 1005*7bd3a2e2SSriharsha Basavapatna } 1006*7bd3a2e2SSriharsha Basavapatna pub_addr->hdr.dstate = VIO_DESC_FREE; 1007*7bd3a2e2SSriharsha Basavapatna priv_addr->dstate = VIO_DESC_FREE; 1008*7bd3a2e2SSriharsha Basavapatna /* clear all the fields */ 1009*7bd3a2e2SSriharsha Basavapatna priv_addr->datalen = 0; 1010*7bd3a2e2SSriharsha Basavapatna pub_addr->hdr.ack = 0; 1011*7bd3a2e2SSriharsha Basavapatna mutex_exit(&priv_addr->dstate_lock); 1012*7bd3a2e2SSriharsha Basavapatna 1013*7bd3a2e2SSriharsha Basavapatna D3(NULL, "claiming descp:%d pub state:0x%llx priv state 0x%llx", 1014*7bd3a2e2SSriharsha Basavapatna i, pub_addr->hdr.dstate, priv_addr->dstate); 1015*7bd3a2e2SSriharsha Basavapatna } 1016*7bd3a2e2SSriharsha Basavapatna return (j); 1017*7bd3a2e2SSriharsha Basavapatna } 1018*7bd3a2e2SSriharsha Basavapatna 1019*7bd3a2e2SSriharsha Basavapatna void 1020*7bd3a2e2SSriharsha Basavapatna vsw_process_dringdata(void *arg, void *dpkt) 1021*7bd3a2e2SSriharsha Basavapatna { 1022*7bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = arg; 1023*7bd3a2e2SSriharsha Basavapatna vio_dring_msg_t *dring_pkt; 1024*7bd3a2e2SSriharsha Basavapatna vnet_public_desc_t desc, *pub_addr = NULL; 1025*7bd3a2e2SSriharsha Basavapatna vsw_private_desc_t *priv_addr = NULL; 1026*7bd3a2e2SSriharsha Basavapatna dring_info_t *dp = NULL; 1027*7bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 1028*7bd3a2e2SSriharsha Basavapatna mblk_t *mp = NULL; 1029*7bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp = NULL; 1030*7bd3a2e2SSriharsha Basavapatna mblk_t *bp = NULL; 1031*7bd3a2e2SSriharsha Basavapatna mblk_t *bpt = NULL; 1032*7bd3a2e2SSriharsha Basavapatna size_t nbytes = 0; 1033*7bd3a2e2SSriharsha Basavapatna uint64_t chain = 0; 1034*7bd3a2e2SSriharsha Basavapatna uint64_t len; 1035*7bd3a2e2SSriharsha Basavapatna uint32_t pos, start; 1036*7bd3a2e2SSriharsha Basavapatna uint32_t range_start, range_end; 1037*7bd3a2e2SSriharsha Basavapatna int32_t end, num, cnt = 0; 1038*7bd3a2e2SSriharsha Basavapatna int i, rv, rng_rv = 0, msg_rv = 0; 1039*7bd3a2e2SSriharsha Basavapatna boolean_t prev_desc_ack = B_FALSE; 1040*7bd3a2e2SSriharsha Basavapatna int read_attempts = 0; 1041*7bd3a2e2SSriharsha Basavapatna struct ether_header *ehp; 1042*7bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 1043*7bd3a2e2SSriharsha Basavapatna 1044*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 1045*7bd3a2e2SSriharsha Basavapatna 1046*7bd3a2e2SSriharsha Basavapatna /* 1047*7bd3a2e2SSriharsha Basavapatna * We know this is a data/dring packet so 1048*7bd3a2e2SSriharsha Basavapatna * cast it into the correct structure. 1049*7bd3a2e2SSriharsha Basavapatna */ 1050*7bd3a2e2SSriharsha Basavapatna dring_pkt = (vio_dring_msg_t *)dpkt; 1051*7bd3a2e2SSriharsha Basavapatna 1052*7bd3a2e2SSriharsha Basavapatna /* 1053*7bd3a2e2SSriharsha Basavapatna * Switch on the vio_subtype. If its INFO then we need to 1054*7bd3a2e2SSriharsha Basavapatna * process the data. If its an ACK we need to make sure 1055*7bd3a2e2SSriharsha Basavapatna * it makes sense (i.e did we send an earlier data/info), 1056*7bd3a2e2SSriharsha Basavapatna * and if its a NACK then we maybe attempt a retry. 1057*7bd3a2e2SSriharsha Basavapatna */ 1058*7bd3a2e2SSriharsha Basavapatna switch (dring_pkt->tag.vio_subtype) { 1059*7bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO: 1060*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): VIO_SUBTYPE_INFO", __func__, ldcp->ldc_id); 1061*7bd3a2e2SSriharsha Basavapatna 1062*7bd3a2e2SSriharsha Basavapatna dp = ldcp->lane_in.dringp; 1063*7bd3a2e2SSriharsha Basavapatna if (dp->ident != dring_pkt->dring_ident) { 1064*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): unable to find dring from " 1065*7bd3a2e2SSriharsha Basavapatna "ident 0x%llx", __func__, ldcp->ldc_id, 1066*7bd3a2e2SSriharsha Basavapatna dring_pkt->dring_ident); 1067*7bd3a2e2SSriharsha Basavapatna 1068*7bd3a2e2SSriharsha Basavapatna SND_DRING_NACK(ldcp, dring_pkt); 1069*7bd3a2e2SSriharsha Basavapatna return; 1070*7bd3a2e2SSriharsha Basavapatna } 1071*7bd3a2e2SSriharsha Basavapatna 1072*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_data_msgs_rcvd++; 1073*7bd3a2e2SSriharsha Basavapatna 1074*7bd3a2e2SSriharsha Basavapatna start = pos = dring_pkt->start_idx; 1075*7bd3a2e2SSriharsha Basavapatna end = dring_pkt->end_idx; 1076*7bd3a2e2SSriharsha Basavapatna len = dp->num_descriptors; 1077*7bd3a2e2SSriharsha Basavapatna 1078*7bd3a2e2SSriharsha Basavapatna range_start = range_end = pos; 1079*7bd3a2e2SSriharsha Basavapatna 1080*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): start index %ld : end %ld\n", 1081*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, start, end); 1082*7bd3a2e2SSriharsha Basavapatna 1083*7bd3a2e2SSriharsha Basavapatna if (end == -1) { 1084*7bd3a2e2SSriharsha Basavapatna num = -1; 1085*7bd3a2e2SSriharsha Basavapatna } else if (end >= 0) { 1086*7bd3a2e2SSriharsha Basavapatna num = end >= pos ? end - pos + 1: (len - pos + 1) + end; 1087*7bd3a2e2SSriharsha Basavapatna 1088*7bd3a2e2SSriharsha Basavapatna /* basic sanity check */ 1089*7bd3a2e2SSriharsha Basavapatna if (end > len) { 1090*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): endpoint %lld outside " 1091*7bd3a2e2SSriharsha Basavapatna "ring length %lld", __func__, 1092*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, end, len); 1093*7bd3a2e2SSriharsha Basavapatna 1094*7bd3a2e2SSriharsha Basavapatna SND_DRING_NACK(ldcp, dring_pkt); 1095*7bd3a2e2SSriharsha Basavapatna return; 1096*7bd3a2e2SSriharsha Basavapatna } 1097*7bd3a2e2SSriharsha Basavapatna } else { 1098*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): invalid endpoint %lld", 1099*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, end); 1100*7bd3a2e2SSriharsha Basavapatna SND_DRING_NACK(ldcp, dring_pkt); 1101*7bd3a2e2SSriharsha Basavapatna return; 1102*7bd3a2e2SSriharsha Basavapatna } 1103*7bd3a2e2SSriharsha Basavapatna 1104*7bd3a2e2SSriharsha Basavapatna while (cnt != num) { 1105*7bd3a2e2SSriharsha Basavapatna vsw_recheck_desc: 1106*7bd3a2e2SSriharsha Basavapatna pub_addr = (vnet_public_desc_t *)dp->pub_addr + pos; 1107*7bd3a2e2SSriharsha Basavapatna 1108*7bd3a2e2SSriharsha Basavapatna if ((rng_rv = vnet_dring_entry_copy(pub_addr, 1109*7bd3a2e2SSriharsha Basavapatna &desc, dp->dring_mtype, dp->dring_handle, 1110*7bd3a2e2SSriharsha Basavapatna pos, pos)) != 0) { 1111*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): unable to copy " 1112*7bd3a2e2SSriharsha Basavapatna "descriptor at pos %d: err %d", 1113*7bd3a2e2SSriharsha Basavapatna __func__, pos, ldcp->ldc_id, rng_rv); 1114*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.ierrors++; 1115*7bd3a2e2SSriharsha Basavapatna break; 1116*7bd3a2e2SSriharsha Basavapatna } 1117*7bd3a2e2SSriharsha Basavapatna 1118*7bd3a2e2SSriharsha Basavapatna /* 1119*7bd3a2e2SSriharsha Basavapatna * When given a bounded range of descriptors 1120*7bd3a2e2SSriharsha Basavapatna * to process, its an error to hit a descriptor 1121*7bd3a2e2SSriharsha Basavapatna * which is not ready. In the non-bounded case 1122*7bd3a2e2SSriharsha Basavapatna * (end_idx == -1) this simply indicates we have 1123*7bd3a2e2SSriharsha Basavapatna * reached the end of the current active range. 1124*7bd3a2e2SSriharsha Basavapatna */ 1125*7bd3a2e2SSriharsha Basavapatna if (desc.hdr.dstate != VIO_DESC_READY) { 1126*7bd3a2e2SSriharsha Basavapatna /* unbound - no error */ 1127*7bd3a2e2SSriharsha Basavapatna if (end == -1) { 1128*7bd3a2e2SSriharsha Basavapatna if (read_attempts == vsw_recv_retries) 1129*7bd3a2e2SSriharsha Basavapatna break; 1130*7bd3a2e2SSriharsha Basavapatna 1131*7bd3a2e2SSriharsha Basavapatna delay(drv_usectohz(vsw_recv_delay)); 1132*7bd3a2e2SSriharsha Basavapatna read_attempts++; 1133*7bd3a2e2SSriharsha Basavapatna goto vsw_recheck_desc; 1134*7bd3a2e2SSriharsha Basavapatna } 1135*7bd3a2e2SSriharsha Basavapatna 1136*7bd3a2e2SSriharsha Basavapatna /* bounded - error - so NACK back */ 1137*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): descriptor not READY " 1138*7bd3a2e2SSriharsha Basavapatna "(%d)", __func__, ldcp->ldc_id, 1139*7bd3a2e2SSriharsha Basavapatna desc.hdr.dstate); 1140*7bd3a2e2SSriharsha Basavapatna SND_DRING_NACK(ldcp, dring_pkt); 1141*7bd3a2e2SSriharsha Basavapatna return; 1142*7bd3a2e2SSriharsha Basavapatna } 1143*7bd3a2e2SSriharsha Basavapatna 1144*7bd3a2e2SSriharsha Basavapatna DTRACE_PROBE1(read_attempts, int, read_attempts); 1145*7bd3a2e2SSriharsha Basavapatna 1146*7bd3a2e2SSriharsha Basavapatna range_end = pos; 1147*7bd3a2e2SSriharsha Basavapatna 1148*7bd3a2e2SSriharsha Basavapatna /* 1149*7bd3a2e2SSriharsha Basavapatna * If we ACK'd the previous descriptor then now 1150*7bd3a2e2SSriharsha Basavapatna * record the new range start position for later 1151*7bd3a2e2SSriharsha Basavapatna * ACK's. 1152*7bd3a2e2SSriharsha Basavapatna */ 1153*7bd3a2e2SSriharsha Basavapatna if (prev_desc_ack) { 1154*7bd3a2e2SSriharsha Basavapatna range_start = pos; 1155*7bd3a2e2SSriharsha Basavapatna 1156*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): updating range start to be " 1157*7bd3a2e2SSriharsha Basavapatna "%d", __func__, ldcp->ldc_id, range_start); 1158*7bd3a2e2SSriharsha Basavapatna 1159*7bd3a2e2SSriharsha Basavapatna prev_desc_ack = B_FALSE; 1160*7bd3a2e2SSriharsha Basavapatna } 1161*7bd3a2e2SSriharsha Basavapatna 1162*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): processing desc %lld at pos" 1163*7bd3a2e2SSriharsha Basavapatna " 0x%llx : dstate 0x%lx : datalen 0x%lx", 1164*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, pos, &desc, 1165*7bd3a2e2SSriharsha Basavapatna desc.hdr.dstate, desc.nbytes); 1166*7bd3a2e2SSriharsha Basavapatna 1167*7bd3a2e2SSriharsha Basavapatna if ((desc.nbytes < ETHERMIN) || 1168*7bd3a2e2SSriharsha Basavapatna (desc.nbytes > lp->mtu)) { 1169*7bd3a2e2SSriharsha Basavapatna /* invalid size; drop the packet */ 1170*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.ierrors++; 1171*7bd3a2e2SSriharsha Basavapatna goto vsw_process_desc_done; 1172*7bd3a2e2SSriharsha Basavapatna } 1173*7bd3a2e2SSriharsha Basavapatna 1174*7bd3a2e2SSriharsha Basavapatna /* 1175*7bd3a2e2SSriharsha Basavapatna * Ensure that we ask ldc for an aligned 1176*7bd3a2e2SSriharsha Basavapatna * number of bytes. Data is padded to align on 8 1177*7bd3a2e2SSriharsha Basavapatna * byte boundary, desc.nbytes is actual data length, 1178*7bd3a2e2SSriharsha Basavapatna * i.e. minus that padding. 1179*7bd3a2e2SSriharsha Basavapatna */ 1180*7bd3a2e2SSriharsha Basavapatna nbytes = (desc.nbytes + VNET_IPALIGN + 7) & ~7; 1181*7bd3a2e2SSriharsha Basavapatna if (nbytes > ldcp->max_rxpool_size) { 1182*7bd3a2e2SSriharsha Basavapatna mp = allocb(desc.nbytes + VNET_IPALIGN + 8, 1183*7bd3a2e2SSriharsha Basavapatna BPRI_MED); 1184*7bd3a2e2SSriharsha Basavapatna vmp = NULL; 1185*7bd3a2e2SSriharsha Basavapatna } else { 1186*7bd3a2e2SSriharsha Basavapatna vmp = vio_multipool_allocb(&ldcp->vmp, nbytes); 1187*7bd3a2e2SSriharsha Basavapatna if (vmp == NULL) { 1188*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.rx_vio_allocb_fail++; 1189*7bd3a2e2SSriharsha Basavapatna /* 1190*7bd3a2e2SSriharsha Basavapatna * No free receive buffers available, 1191*7bd3a2e2SSriharsha Basavapatna * so fallback onto allocb(9F). Make 1192*7bd3a2e2SSriharsha Basavapatna * sure that we get a data buffer which 1193*7bd3a2e2SSriharsha Basavapatna * is a multiple of 8 as this is 1194*7bd3a2e2SSriharsha Basavapatna * required by ldc_mem_copy. 1195*7bd3a2e2SSriharsha Basavapatna */ 1196*7bd3a2e2SSriharsha Basavapatna DTRACE_PROBE(allocb); 1197*7bd3a2e2SSriharsha Basavapatna mp = allocb(desc.nbytes + 1198*7bd3a2e2SSriharsha Basavapatna VNET_IPALIGN + 8, BPRI_MED); 1199*7bd3a2e2SSriharsha Basavapatna } else { 1200*7bd3a2e2SSriharsha Basavapatna mp = vmp->mp; 1201*7bd3a2e2SSriharsha Basavapatna } 1202*7bd3a2e2SSriharsha Basavapatna } 1203*7bd3a2e2SSriharsha Basavapatna if (mp == NULL) { 1204*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%ld): allocb failed", 1205*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 1206*7bd3a2e2SSriharsha Basavapatna rng_rv = vnet_dring_entry_set_dstate(pub_addr, 1207*7bd3a2e2SSriharsha Basavapatna dp->dring_mtype, dp->dring_handle, pos, pos, 1208*7bd3a2e2SSriharsha Basavapatna VIO_DESC_DONE); 1209*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.ierrors++; 1210*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.rx_allocb_fail++; 1211*7bd3a2e2SSriharsha Basavapatna break; 1212*7bd3a2e2SSriharsha Basavapatna } 1213*7bd3a2e2SSriharsha Basavapatna 1214*7bd3a2e2SSriharsha Basavapatna rv = ldc_mem_copy(ldcp->ldc_handle, 1215*7bd3a2e2SSriharsha Basavapatna (caddr_t)mp->b_rptr, 0, &nbytes, 1216*7bd3a2e2SSriharsha Basavapatna desc.memcookie, desc.ncookies, LDC_COPY_IN); 1217*7bd3a2e2SSriharsha Basavapatna if (rv != 0) { 1218*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%d): unable to copy in data " 1219*7bd3a2e2SSriharsha Basavapatna "from %d cookies in desc %d (rv %d)", 1220*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, desc.ncookies, 1221*7bd3a2e2SSriharsha Basavapatna pos, rv); 1222*7bd3a2e2SSriharsha Basavapatna freemsg(mp); 1223*7bd3a2e2SSriharsha Basavapatna 1224*7bd3a2e2SSriharsha Basavapatna rng_rv = vnet_dring_entry_set_dstate(pub_addr, 1225*7bd3a2e2SSriharsha Basavapatna dp->dring_mtype, dp->dring_handle, pos, pos, 1226*7bd3a2e2SSriharsha Basavapatna VIO_DESC_DONE); 1227*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.ierrors++; 1228*7bd3a2e2SSriharsha Basavapatna break; 1229*7bd3a2e2SSriharsha Basavapatna } else { 1230*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%d): copied in %ld bytes" 1231*7bd3a2e2SSriharsha Basavapatna " using %d cookies", __func__, 1232*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, nbytes, desc.ncookies); 1233*7bd3a2e2SSriharsha Basavapatna } 1234*7bd3a2e2SSriharsha Basavapatna 1235*7bd3a2e2SSriharsha Basavapatna /* adjust the read pointer to skip over the padding */ 1236*7bd3a2e2SSriharsha Basavapatna mp->b_rptr += VNET_IPALIGN; 1237*7bd3a2e2SSriharsha Basavapatna 1238*7bd3a2e2SSriharsha Basavapatna /* point to the actual end of data */ 1239*7bd3a2e2SSriharsha Basavapatna mp->b_wptr = mp->b_rptr + desc.nbytes; 1240*7bd3a2e2SSriharsha Basavapatna 1241*7bd3a2e2SSriharsha Basavapatna if (vmp != NULL) { 1242*7bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA; 1243*7bd3a2e2SSriharsha Basavapatna } 1244*7bd3a2e2SSriharsha Basavapatna 1245*7bd3a2e2SSriharsha Basavapatna /* update statistics */ 1246*7bd3a2e2SSriharsha Basavapatna ehp = (struct ether_header *)mp->b_rptr; 1247*7bd3a2e2SSriharsha Basavapatna if (IS_BROADCAST(ehp)) 1248*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.brdcstrcv++; 1249*7bd3a2e2SSriharsha Basavapatna else if (IS_MULTICAST(ehp)) 1250*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.multircv++; 1251*7bd3a2e2SSriharsha Basavapatna 1252*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.ipackets++; 1253*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.rbytes += desc.nbytes; 1254*7bd3a2e2SSriharsha Basavapatna 1255*7bd3a2e2SSriharsha Basavapatna /* 1256*7bd3a2e2SSriharsha Basavapatna * IPALIGN space can be used for VLAN_TAG 1257*7bd3a2e2SSriharsha Basavapatna */ 1258*7bd3a2e2SSriharsha Basavapatna (void) vsw_vlan_frame_pretag(ldcp->ldc_port, 1259*7bd3a2e2SSriharsha Basavapatna VSW_VNETPORT, mp); 1260*7bd3a2e2SSriharsha Basavapatna 1261*7bd3a2e2SSriharsha Basavapatna /* build a chain of received packets */ 1262*7bd3a2e2SSriharsha Basavapatna if (bp == NULL) { 1263*7bd3a2e2SSriharsha Basavapatna /* first pkt */ 1264*7bd3a2e2SSriharsha Basavapatna bp = mp; 1265*7bd3a2e2SSriharsha Basavapatna bp->b_next = bp->b_prev = NULL; 1266*7bd3a2e2SSriharsha Basavapatna bpt = bp; 1267*7bd3a2e2SSriharsha Basavapatna chain = 1; 1268*7bd3a2e2SSriharsha Basavapatna } else { 1269*7bd3a2e2SSriharsha Basavapatna mp->b_next = mp->b_prev = NULL; 1270*7bd3a2e2SSriharsha Basavapatna bpt->b_next = mp; 1271*7bd3a2e2SSriharsha Basavapatna bpt = mp; 1272*7bd3a2e2SSriharsha Basavapatna chain++; 1273*7bd3a2e2SSriharsha Basavapatna } 1274*7bd3a2e2SSriharsha Basavapatna 1275*7bd3a2e2SSriharsha Basavapatna vsw_process_desc_done: 1276*7bd3a2e2SSriharsha Basavapatna /* mark we are finished with this descriptor */ 1277*7bd3a2e2SSriharsha Basavapatna if ((rng_rv = vnet_dring_entry_set_dstate(pub_addr, 1278*7bd3a2e2SSriharsha Basavapatna dp->dring_mtype, dp->dring_handle, pos, pos, 1279*7bd3a2e2SSriharsha Basavapatna VIO_DESC_DONE)) != 0) { 1280*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): unable to update " 1281*7bd3a2e2SSriharsha Basavapatna "dstate at pos %d: err %d", 1282*7bd3a2e2SSriharsha Basavapatna __func__, pos, ldcp->ldc_id, rng_rv); 1283*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.ierrors++; 1284*7bd3a2e2SSriharsha Basavapatna break; 1285*7bd3a2e2SSriharsha Basavapatna } 1286*7bd3a2e2SSriharsha Basavapatna 1287*7bd3a2e2SSriharsha Basavapatna /* 1288*7bd3a2e2SSriharsha Basavapatna * Send an ACK back to peer if requested. 1289*7bd3a2e2SSriharsha Basavapatna */ 1290*7bd3a2e2SSriharsha Basavapatna if (desc.hdr.ack) { 1291*7bd3a2e2SSriharsha Basavapatna dring_pkt->start_idx = range_start; 1292*7bd3a2e2SSriharsha Basavapatna dring_pkt->end_idx = range_end; 1293*7bd3a2e2SSriharsha Basavapatna 1294*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): processed %d %d, ACK" 1295*7bd3a2e2SSriharsha Basavapatna " requested", __func__, ldcp->ldc_id, 1296*7bd3a2e2SSriharsha Basavapatna dring_pkt->start_idx, dring_pkt->end_idx); 1297*7bd3a2e2SSriharsha Basavapatna 1298*7bd3a2e2SSriharsha Basavapatna dring_pkt->dring_process_state = VIO_DP_ACTIVE; 1299*7bd3a2e2SSriharsha Basavapatna dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK; 1300*7bd3a2e2SSriharsha Basavapatna dring_pkt->tag.vio_sid = ldcp->local_session; 1301*7bd3a2e2SSriharsha Basavapatna 1302*7bd3a2e2SSriharsha Basavapatna msg_rv = vsw_send_msg(ldcp, (void *)dring_pkt, 1303*7bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_FALSE); 1304*7bd3a2e2SSriharsha Basavapatna 1305*7bd3a2e2SSriharsha Basavapatna /* 1306*7bd3a2e2SSriharsha Basavapatna * Check if ACK was successfully sent. If not 1307*7bd3a2e2SSriharsha Basavapatna * we break and deal with that below. 1308*7bd3a2e2SSriharsha Basavapatna */ 1309*7bd3a2e2SSriharsha Basavapatna if (msg_rv != 0) 1310*7bd3a2e2SSriharsha Basavapatna break; 1311*7bd3a2e2SSriharsha Basavapatna 1312*7bd3a2e2SSriharsha Basavapatna prev_desc_ack = B_TRUE; 1313*7bd3a2e2SSriharsha Basavapatna range_start = pos; 1314*7bd3a2e2SSriharsha Basavapatna } 1315*7bd3a2e2SSriharsha Basavapatna 1316*7bd3a2e2SSriharsha Basavapatna /* next descriptor */ 1317*7bd3a2e2SSriharsha Basavapatna pos = (pos + 1) % len; 1318*7bd3a2e2SSriharsha Basavapatna cnt++; 1319*7bd3a2e2SSriharsha Basavapatna 1320*7bd3a2e2SSriharsha Basavapatna /* 1321*7bd3a2e2SSriharsha Basavapatna * Break out of loop here and stop processing to 1322*7bd3a2e2SSriharsha Basavapatna * allow some other network device (or disk) to 1323*7bd3a2e2SSriharsha Basavapatna * get access to the cpu. 1324*7bd3a2e2SSriharsha Basavapatna */ 1325*7bd3a2e2SSriharsha Basavapatna if (chain > vsw_chain_len) { 1326*7bd3a2e2SSriharsha Basavapatna D3(vswp, "%s(%lld): switching chain of %d " 1327*7bd3a2e2SSriharsha Basavapatna "msgs", __func__, ldcp->ldc_id, chain); 1328*7bd3a2e2SSriharsha Basavapatna break; 1329*7bd3a2e2SSriharsha Basavapatna } 1330*7bd3a2e2SSriharsha Basavapatna } 1331*7bd3a2e2SSriharsha Basavapatna 1332*7bd3a2e2SSriharsha Basavapatna /* send the chain of packets to be switched */ 1333*7bd3a2e2SSriharsha Basavapatna if (bp != NULL) { 1334*7bd3a2e2SSriharsha Basavapatna DTRACE_PROBE1(vsw_rcv_msgs, int, chain); 1335*7bd3a2e2SSriharsha Basavapatna D3(vswp, "%s(%lld): switching chain of %d msgs", 1336*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, chain); 1337*7bd3a2e2SSriharsha Basavapatna vswp->vsw_switch_frame(vswp, bp, VSW_VNETPORT, 1338*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_port, NULL); 1339*7bd3a2e2SSriharsha Basavapatna } 1340*7bd3a2e2SSriharsha Basavapatna 1341*7bd3a2e2SSriharsha Basavapatna /* 1342*7bd3a2e2SSriharsha Basavapatna * If when we encountered an error when attempting to 1343*7bd3a2e2SSriharsha Basavapatna * access an imported dring, initiate a connection reset. 1344*7bd3a2e2SSriharsha Basavapatna */ 1345*7bd3a2e2SSriharsha Basavapatna if (rng_rv != 0) { 1346*7bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 1347*7bd3a2e2SSriharsha Basavapatna break; 1348*7bd3a2e2SSriharsha Basavapatna } 1349*7bd3a2e2SSriharsha Basavapatna 1350*7bd3a2e2SSriharsha Basavapatna /* 1351*7bd3a2e2SSriharsha Basavapatna * If when we attempted to send the ACK we found that the 1352*7bd3a2e2SSriharsha Basavapatna * channel had been reset then now handle this. 1353*7bd3a2e2SSriharsha Basavapatna */ 1354*7bd3a2e2SSriharsha Basavapatna if (msg_rv == ECONNRESET) { 1355*7bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 1356*7bd3a2e2SSriharsha Basavapatna break; 1357*7bd3a2e2SSriharsha Basavapatna } 1358*7bd3a2e2SSriharsha Basavapatna 1359*7bd3a2e2SSriharsha Basavapatna DTRACE_PROBE1(msg_cnt, int, cnt); 1360*7bd3a2e2SSriharsha Basavapatna 1361*7bd3a2e2SSriharsha Basavapatna /* 1362*7bd3a2e2SSriharsha Basavapatna * We are now finished so ACK back with the state 1363*7bd3a2e2SSriharsha Basavapatna * set to STOPPING so our peer knows we are finished 1364*7bd3a2e2SSriharsha Basavapatna */ 1365*7bd3a2e2SSriharsha Basavapatna dring_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK; 1366*7bd3a2e2SSriharsha Basavapatna dring_pkt->tag.vio_sid = ldcp->local_session; 1367*7bd3a2e2SSriharsha Basavapatna 1368*7bd3a2e2SSriharsha Basavapatna dring_pkt->dring_process_state = VIO_DP_STOPPED; 1369*7bd3a2e2SSriharsha Basavapatna 1370*7bd3a2e2SSriharsha Basavapatna DTRACE_PROBE(stop_process_sent); 1371*7bd3a2e2SSriharsha Basavapatna 1372*7bd3a2e2SSriharsha Basavapatna /* 1373*7bd3a2e2SSriharsha Basavapatna * We have not processed any more descriptors beyond 1374*7bd3a2e2SSriharsha Basavapatna * the last one we ACK'd. 1375*7bd3a2e2SSriharsha Basavapatna */ 1376*7bd3a2e2SSriharsha Basavapatna if (prev_desc_ack) 1377*7bd3a2e2SSriharsha Basavapatna range_start = range_end; 1378*7bd3a2e2SSriharsha Basavapatna 1379*7bd3a2e2SSriharsha Basavapatna dring_pkt->start_idx = range_start; 1380*7bd3a2e2SSriharsha Basavapatna dring_pkt->end_idx = range_end; 1381*7bd3a2e2SSriharsha Basavapatna 1382*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld) processed : %d : %d, now stopping", 1383*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, dring_pkt->start_idx, 1384*7bd3a2e2SSriharsha Basavapatna dring_pkt->end_idx); 1385*7bd3a2e2SSriharsha Basavapatna 1386*7bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)dring_pkt, 1387*7bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_TRUE); 1388*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_data_acks_sent++; 1389*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_stopped_acks_sent++; 1390*7bd3a2e2SSriharsha Basavapatna break; 1391*7bd3a2e2SSriharsha Basavapatna 1392*7bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK: 1393*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): VIO_SUBTYPE_ACK", __func__, ldcp->ldc_id); 1394*7bd3a2e2SSriharsha Basavapatna /* 1395*7bd3a2e2SSriharsha Basavapatna * Verify that the relevant descriptors are all 1396*7bd3a2e2SSriharsha Basavapatna * marked as DONE 1397*7bd3a2e2SSriharsha Basavapatna */ 1398*7bd3a2e2SSriharsha Basavapatna dp = ldcp->lane_out.dringp; 1399*7bd3a2e2SSriharsha Basavapatna if (dp->ident != dring_pkt->dring_ident) { 1400*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: unknown ident in ACK", __func__); 1401*7bd3a2e2SSriharsha Basavapatna return; 1402*7bd3a2e2SSriharsha Basavapatna } 1403*7bd3a2e2SSriharsha Basavapatna 1404*7bd3a2e2SSriharsha Basavapatna start = end = 0; 1405*7bd3a2e2SSriharsha Basavapatna start = dring_pkt->start_idx; 1406*7bd3a2e2SSriharsha Basavapatna end = dring_pkt->end_idx; 1407*7bd3a2e2SSriharsha Basavapatna len = dp->num_descriptors; 1408*7bd3a2e2SSriharsha Basavapatna 1409*7bd3a2e2SSriharsha Basavapatna 1410*7bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->dlock); 1411*7bd3a2e2SSriharsha Basavapatna dp->last_ack_recv = end; 1412*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_data_acks_rcvd++; 1413*7bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->dlock); 1414*7bd3a2e2SSriharsha Basavapatna 1415*7bd3a2e2SSriharsha Basavapatna (void) vsw_reclaim_dring(dp, start); 1416*7bd3a2e2SSriharsha Basavapatna 1417*7bd3a2e2SSriharsha Basavapatna /* 1418*7bd3a2e2SSriharsha Basavapatna * If our peer is stopping processing descriptors then 1419*7bd3a2e2SSriharsha Basavapatna * we check to make sure it has processed all the descriptors 1420*7bd3a2e2SSriharsha Basavapatna * we have updated. If not then we send it a new message 1421*7bd3a2e2SSriharsha Basavapatna * to prompt it to restart. 1422*7bd3a2e2SSriharsha Basavapatna */ 1423*7bd3a2e2SSriharsha Basavapatna if (dring_pkt->dring_process_state == VIO_DP_STOPPED) { 1424*7bd3a2e2SSriharsha Basavapatna DTRACE_PROBE(stop_process_recv); 1425*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld): got stopping msg : %d : %d", 1426*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, dring_pkt->start_idx, 1427*7bd3a2e2SSriharsha Basavapatna dring_pkt->end_idx); 1428*7bd3a2e2SSriharsha Basavapatna 1429*7bd3a2e2SSriharsha Basavapatna /* 1430*7bd3a2e2SSriharsha Basavapatna * Check next descriptor in public section of ring. 1431*7bd3a2e2SSriharsha Basavapatna * If its marked as READY then we need to prompt our 1432*7bd3a2e2SSriharsha Basavapatna * peer to start processing the ring again. 1433*7bd3a2e2SSriharsha Basavapatna */ 1434*7bd3a2e2SSriharsha Basavapatna i = (end + 1) % len; 1435*7bd3a2e2SSriharsha Basavapatna pub_addr = (vnet_public_desc_t *)dp->pub_addr + i; 1436*7bd3a2e2SSriharsha Basavapatna priv_addr = (vsw_private_desc_t *)dp->priv_addr + i; 1437*7bd3a2e2SSriharsha Basavapatna 1438*7bd3a2e2SSriharsha Basavapatna /* 1439*7bd3a2e2SSriharsha Basavapatna * Hold the restart lock across all of this to 1440*7bd3a2e2SSriharsha Basavapatna * make sure that its not possible for us to 1441*7bd3a2e2SSriharsha Basavapatna * decide that a msg needs to be sent in the future 1442*7bd3a2e2SSriharsha Basavapatna * but the sending code having already checked is 1443*7bd3a2e2SSriharsha Basavapatna * about to exit. 1444*7bd3a2e2SSriharsha Basavapatna */ 1445*7bd3a2e2SSriharsha Basavapatna mutex_enter(&dp->restart_lock); 1446*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_stopped_acks_rcvd++; 1447*7bd3a2e2SSriharsha Basavapatna mutex_enter(&priv_addr->dstate_lock); 1448*7bd3a2e2SSriharsha Basavapatna if (pub_addr->hdr.dstate == VIO_DESC_READY) { 1449*7bd3a2e2SSriharsha Basavapatna 1450*7bd3a2e2SSriharsha Basavapatna mutex_exit(&priv_addr->dstate_lock); 1451*7bd3a2e2SSriharsha Basavapatna 1452*7bd3a2e2SSriharsha Basavapatna dring_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO; 1453*7bd3a2e2SSriharsha Basavapatna dring_pkt->tag.vio_sid = ldcp->local_session; 1454*7bd3a2e2SSriharsha Basavapatna 1455*7bd3a2e2SSriharsha Basavapatna dring_pkt->start_idx = (end + 1) % len; 1456*7bd3a2e2SSriharsha Basavapatna dring_pkt->end_idx = -1; 1457*7bd3a2e2SSriharsha Basavapatna 1458*7bd3a2e2SSriharsha Basavapatna D2(vswp, "%s(%lld) : sending restart msg:" 1459*7bd3a2e2SSriharsha Basavapatna " %d : %d", __func__, ldcp->ldc_id, 1460*7bd3a2e2SSriharsha Basavapatna dring_pkt->start_idx, dring_pkt->end_idx); 1461*7bd3a2e2SSriharsha Basavapatna 1462*7bd3a2e2SSriharsha Basavapatna msg_rv = vsw_send_msg(ldcp, (void *)dring_pkt, 1463*7bd3a2e2SSriharsha Basavapatna sizeof (vio_dring_msg_t), B_FALSE); 1464*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_stats.dring_data_msgs_sent++; 1465*7bd3a2e2SSriharsha Basavapatna 1466*7bd3a2e2SSriharsha Basavapatna } else { 1467*7bd3a2e2SSriharsha Basavapatna mutex_exit(&priv_addr->dstate_lock); 1468*7bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE; 1469*7bd3a2e2SSriharsha Basavapatna } 1470*7bd3a2e2SSriharsha Basavapatna mutex_exit(&dp->restart_lock); 1471*7bd3a2e2SSriharsha Basavapatna } 1472*7bd3a2e2SSriharsha Basavapatna 1473*7bd3a2e2SSriharsha Basavapatna if (msg_rv == ECONNRESET) 1474*7bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 1475*7bd3a2e2SSriharsha Basavapatna 1476*7bd3a2e2SSriharsha Basavapatna break; 1477*7bd3a2e2SSriharsha Basavapatna 1478*7bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_NACK: 1479*7bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld): VIO_SUBTYPE_NACK", 1480*7bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 1481*7bd3a2e2SSriharsha Basavapatna /* 1482*7bd3a2e2SSriharsha Basavapatna * Something is badly wrong if we are getting NACK's 1483*7bd3a2e2SSriharsha Basavapatna * for our data pkts. So reset the channel. 1484*7bd3a2e2SSriharsha Basavapatna */ 1485*7bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 1486*7bd3a2e2SSriharsha Basavapatna 1487*7bd3a2e2SSriharsha Basavapatna break; 1488*7bd3a2e2SSriharsha Basavapatna 1489*7bd3a2e2SSriharsha Basavapatna default: 1490*7bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__, 1491*7bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, dring_pkt->tag.vio_subtype); 1492*7bd3a2e2SSriharsha Basavapatna } 1493*7bd3a2e2SSriharsha Basavapatna 1494*7bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id); 1495*7bd3a2e2SSriharsha Basavapatna } 1496