xref: /illumos-gate/usr/src/uts/sun4v/io/vsw_rxdring.c (revision 6e472272d020cb1e83ec4964e2a2f5761a354bcb)
17bd3a2e2SSriharsha Basavapatna /*
27bd3a2e2SSriharsha Basavapatna  * CDDL HEADER START
37bd3a2e2SSriharsha Basavapatna  *
47bd3a2e2SSriharsha Basavapatna  * The contents of this file are subject to the terms of the
57bd3a2e2SSriharsha Basavapatna  * Common Development and Distribution License (the "License").
67bd3a2e2SSriharsha Basavapatna  * You may not use this file except in compliance with the License.
77bd3a2e2SSriharsha Basavapatna  *
87bd3a2e2SSriharsha Basavapatna  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97bd3a2e2SSriharsha Basavapatna  * or http://www.opensolaris.org/os/licensing.
107bd3a2e2SSriharsha Basavapatna  * See the License for the specific language governing permissions
117bd3a2e2SSriharsha Basavapatna  * and limitations under the License.
127bd3a2e2SSriharsha Basavapatna  *
137bd3a2e2SSriharsha Basavapatna  * When distributing Covered Code, include this CDDL HEADER in each
147bd3a2e2SSriharsha Basavapatna  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157bd3a2e2SSriharsha Basavapatna  * If applicable, add the following below this CDDL HEADER, with the
167bd3a2e2SSriharsha Basavapatna  * fields enclosed by brackets "[]" replaced with your own identifying
177bd3a2e2SSriharsha Basavapatna  * information: Portions Copyright [yyyy] [name of copyright owner]
187bd3a2e2SSriharsha Basavapatna  *
197bd3a2e2SSriharsha Basavapatna  * CDDL HEADER END
207bd3a2e2SSriharsha Basavapatna  */
217bd3a2e2SSriharsha Basavapatna 
227bd3a2e2SSriharsha Basavapatna /*
238e512277SWENTAO YANG  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
247bd3a2e2SSriharsha Basavapatna  */
258e512277SWENTAO YANG 
267bd3a2e2SSriharsha Basavapatna #include <sys/types.h>
277bd3a2e2SSriharsha Basavapatna #include <sys/errno.h>
287bd3a2e2SSriharsha Basavapatna #include <sys/sysmacros.h>
297bd3a2e2SSriharsha Basavapatna #include <sys/param.h>
307bd3a2e2SSriharsha Basavapatna #include <sys/machsystm.h>
317bd3a2e2SSriharsha Basavapatna #include <sys/stream.h>
327bd3a2e2SSriharsha Basavapatna #include <sys/strsubr.h>
337bd3a2e2SSriharsha Basavapatna #include <sys/kmem.h>
347bd3a2e2SSriharsha Basavapatna #include <sys/strsun.h>
357bd3a2e2SSriharsha Basavapatna #include <sys/callb.h>
367bd3a2e2SSriharsha Basavapatna #include <sys/sdt.h>
377bd3a2e2SSriharsha Basavapatna #include <sys/mach_descrip.h>
387bd3a2e2SSriharsha Basavapatna #include <sys/mdeg.h>
397bd3a2e2SSriharsha Basavapatna #include <net/if.h>
407bd3a2e2SSriharsha Basavapatna #include <sys/vsw.h>
417bd3a2e2SSriharsha Basavapatna #include <sys/vio_mailbox.h>
427bd3a2e2SSriharsha Basavapatna #include <sys/vio_common.h>
437bd3a2e2SSriharsha Basavapatna #include <sys/vnet_common.h>
447bd3a2e2SSriharsha Basavapatna #include <sys/vnet_mailbox.h>
457bd3a2e2SSriharsha Basavapatna #include <sys/vio_util.h>
467bd3a2e2SSriharsha Basavapatna 
477bd3a2e2SSriharsha Basavapatna /*
487bd3a2e2SSriharsha Basavapatna  * This file contains the implementation of RxDringData transfer mode of VIO
497bd3a2e2SSriharsha Basavapatna  * Protocol in vsw. The functions in this file are invoked from vsw_ldc.c
507bd3a2e2SSriharsha Basavapatna  * after RxDringData mode is negotiated with the peer during attribute phase of
517bd3a2e2SSriharsha Basavapatna  * handshake. This file contains functions that setup the transmit and receive
527bd3a2e2SSriharsha Basavapatna  * descriptor rings, and associated resources in RxDringData mode. It also
537bd3a2e2SSriharsha Basavapatna  * contains the transmit and receive data processing functions that are invoked
547bd3a2e2SSriharsha Basavapatna  * in RxDringData mode. The data processing routines in this file have the
557bd3a2e2SSriharsha Basavapatna  * suffix '_shm' to indicate the shared memory mechanism used in RxDringData
567bd3a2e2SSriharsha Basavapatna  * mode.
577bd3a2e2SSriharsha Basavapatna  */
587bd3a2e2SSriharsha Basavapatna 
597bd3a2e2SSriharsha Basavapatna /* Functions exported to vsw_ldc.c */
607bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *vsw_create_rx_dring_info(vsw_ldc_t *);
617bd3a2e2SSriharsha Basavapatna void vsw_destroy_rx_dring(vsw_ldc_t *ldcp);
627bd3a2e2SSriharsha Basavapatna dring_info_t *vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt);
637bd3a2e2SSriharsha Basavapatna void vsw_unmap_tx_dring(vsw_ldc_t *ldcp);
647bd3a2e2SSriharsha Basavapatna int vsw_dringsend_shm(vsw_ldc_t *, mblk_t *);
657bd3a2e2SSriharsha Basavapatna void vsw_ldc_rcv_worker(void *arg);
667bd3a2e2SSriharsha Basavapatna void vsw_stop_rcv_thread(vsw_ldc_t *ldcp);
677bd3a2e2SSriharsha Basavapatna void vsw_process_dringdata_shm(void *, void *);
687bd3a2e2SSriharsha Basavapatna 
697bd3a2e2SSriharsha Basavapatna /* Internal functions */
707bd3a2e2SSriharsha Basavapatna static dring_info_t *vsw_create_rx_dring(vsw_ldc_t *);
717bd3a2e2SSriharsha Basavapatna static int vsw_setup_rx_dring(vsw_ldc_t *ldcp, dring_info_t *dp);
727bd3a2e2SSriharsha Basavapatna static void vsw_process_dringdata_info_shm(vsw_ldc_t *ldcp,
737bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t *msg);
747bd3a2e2SSriharsha Basavapatna static void vsw_process_dringdata_ack_shm(vsw_ldc_t *ldcp,
757bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t *msg);
767bd3a2e2SSriharsha Basavapatna static void vsw_ldc_rcv_shm(vsw_ldc_t *ldcp);
777bd3a2e2SSriharsha Basavapatna static int vsw_receive_packet(vsw_ldc_t *ldcp, mblk_t **bp);
787bd3a2e2SSriharsha Basavapatna static int vsw_send_msg_shm(vsw_ldc_t *ldcp, void *msgp, int size,
797bd3a2e2SSriharsha Basavapatna     boolean_t handle_reset);
807bd3a2e2SSriharsha Basavapatna 
817bd3a2e2SSriharsha Basavapatna /* Functions imported from vsw_ldc.c */
827bd3a2e2SSriharsha Basavapatna extern void vsw_process_pkt(void *);
837bd3a2e2SSriharsha Basavapatna extern void vsw_destroy_rxpools(void *);
847bd3a2e2SSriharsha Basavapatna extern dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp,
857bd3a2e2SSriharsha Basavapatna     vio_dring_reg_msg_t *dring_pkt);
867bd3a2e2SSriharsha Basavapatna extern void vsw_process_conn_evt(vsw_ldc_t *, uint16_t);
877bd3a2e2SSriharsha Basavapatna extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
887bd3a2e2SSriharsha Basavapatna 
897bd3a2e2SSriharsha Basavapatna /* Tunables */
907bd3a2e2SSriharsha Basavapatna extern int vsw_wretries;
917bd3a2e2SSriharsha Basavapatna extern int vsw_recv_delay;
927bd3a2e2SSriharsha Basavapatna extern int vsw_recv_retries;
937bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_chain_len;
947bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_descriptors;
957bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_nrbufs_factor;
967bd3a2e2SSriharsha Basavapatna 
977bd3a2e2SSriharsha Basavapatna #define	VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count, total_count)	\
987bd3a2e2SSriharsha Basavapatna {									\
997bd3a2e2SSriharsha Basavapatna 	DTRACE_PROBE2(vsw_rx_pkts, vsw_ldc_t *, (ldcp), int, (count));	\
1007bd3a2e2SSriharsha Basavapatna 	(vswp)->vsw_switch_frame((vswp), (bp), VSW_VNETPORT,		\
1017bd3a2e2SSriharsha Basavapatna 	    (ldcp)->ldc_port, NULL);					\
1027bd3a2e2SSriharsha Basavapatna 	(bp) = (bpt) = NULL;						\
1037bd3a2e2SSriharsha Basavapatna 	(count) = 0;							\
1047bd3a2e2SSriharsha Basavapatna }
1057bd3a2e2SSriharsha Basavapatna 
1067bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *
vsw_create_rx_dring_info(vsw_ldc_t * ldcp)1077bd3a2e2SSriharsha Basavapatna vsw_create_rx_dring_info(vsw_ldc_t *ldcp)
1087bd3a2e2SSriharsha Basavapatna {
1097bd3a2e2SSriharsha Basavapatna 	vio_dring_reg_msg_t	*mp;
1107bd3a2e2SSriharsha Basavapatna 	vio_dring_reg_ext_msg_t	*emsg;
1117bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp;
1127bd3a2e2SSriharsha Basavapatna 	uint8_t			*buf;
1137bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
1147bd3a2e2SSriharsha Basavapatna 
1157bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s enter\n", __func__);
1167bd3a2e2SSriharsha Basavapatna 
1177bd3a2e2SSriharsha Basavapatna 	/*
1187bd3a2e2SSriharsha Basavapatna 	 * If we can't create a dring, obviously no point sending
1197bd3a2e2SSriharsha Basavapatna 	 * a message.
1207bd3a2e2SSriharsha Basavapatna 	 */
1217bd3a2e2SSriharsha Basavapatna 	if ((dp = vsw_create_rx_dring(ldcp)) == NULL)
1227bd3a2e2SSriharsha Basavapatna 		return (NULL);
1237bd3a2e2SSriharsha Basavapatna 
1247bd3a2e2SSriharsha Basavapatna 	mp = kmem_zalloc(VNET_DRING_REG_EXT_MSG_SIZE(dp->data_ncookies),
1257bd3a2e2SSriharsha Basavapatna 	    KM_SLEEP);
1267bd3a2e2SSriharsha Basavapatna 
1277bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_msgtype = VIO_TYPE_CTRL;
1287bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_subtype = VIO_SUBTYPE_INFO;
1297bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_subtype_env = VIO_DRING_REG;
1307bd3a2e2SSriharsha Basavapatna 	mp->tag.vio_sid = ldcp->local_session;
1317bd3a2e2SSriharsha Basavapatna 
1327bd3a2e2SSriharsha Basavapatna 	/* payload */
1337bd3a2e2SSriharsha Basavapatna 	mp->num_descriptors = dp->num_descriptors;
1347bd3a2e2SSriharsha Basavapatna 	mp->descriptor_size = dp->descriptor_size;
1357bd3a2e2SSriharsha Basavapatna 	mp->options = dp->options;
1367bd3a2e2SSriharsha Basavapatna 	mp->ncookies = dp->dring_ncookies;
1377bd3a2e2SSriharsha Basavapatna 	bcopy(&dp->dring_cookie[0], &mp->cookie[0],
1387bd3a2e2SSriharsha Basavapatna 	    sizeof (ldc_mem_cookie_t));
1397bd3a2e2SSriharsha Basavapatna 
1407bd3a2e2SSriharsha Basavapatna 	mp->dring_ident = 0;
1417bd3a2e2SSriharsha Basavapatna 
1427bd3a2e2SSriharsha Basavapatna 	buf = (uint8_t *)mp->cookie;
1437bd3a2e2SSriharsha Basavapatna 
1447bd3a2e2SSriharsha Basavapatna 	/* skip over dring cookies */
1457bd3a2e2SSriharsha Basavapatna 	ASSERT(mp->ncookies == 1);
1467bd3a2e2SSriharsha Basavapatna 	buf += (mp->ncookies * sizeof (ldc_mem_cookie_t));
1477bd3a2e2SSriharsha Basavapatna 
1487bd3a2e2SSriharsha Basavapatna 	emsg = (vio_dring_reg_ext_msg_t *)buf;
1497bd3a2e2SSriharsha Basavapatna 
1507bd3a2e2SSriharsha Basavapatna 	/* copy data_ncookies in the msg */
1517bd3a2e2SSriharsha Basavapatna 	emsg->data_ncookies = dp->data_ncookies;
1527bd3a2e2SSriharsha Basavapatna 
1537bd3a2e2SSriharsha Basavapatna 	/* copy data area size in the msg */
1547bd3a2e2SSriharsha Basavapatna 	emsg->data_area_size = dp->data_sz;
1557bd3a2e2SSriharsha Basavapatna 
1567bd3a2e2SSriharsha Basavapatna 	/* copy data area cookies in the msg */
1577bd3a2e2SSriharsha Basavapatna 	bcopy(dp->data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie,
1587bd3a2e2SSriharsha Basavapatna 	    sizeof (ldc_mem_cookie_t) * dp->data_ncookies);
1597bd3a2e2SSriharsha Basavapatna 
1607bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s exit\n", __func__);
1617bd3a2e2SSriharsha Basavapatna 
1627bd3a2e2SSriharsha Basavapatna 	return (mp);
1637bd3a2e2SSriharsha Basavapatna }
1647bd3a2e2SSriharsha Basavapatna 
1657bd3a2e2SSriharsha Basavapatna /*
1667bd3a2e2SSriharsha Basavapatna  * Allocate receive resources for the channel. The resources consist of a
1677bd3a2e2SSriharsha Basavapatna  * receive descriptor ring and an associated receive buffer area.
1687bd3a2e2SSriharsha Basavapatna  */
1697bd3a2e2SSriharsha Basavapatna static dring_info_t *
vsw_create_rx_dring(vsw_ldc_t * ldcp)1707bd3a2e2SSriharsha Basavapatna vsw_create_rx_dring(vsw_ldc_t *ldcp)
1717bd3a2e2SSriharsha Basavapatna {
1727bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
1737bd3a2e2SSriharsha Basavapatna 	ldc_mem_info_t		minfo;
1747bd3a2e2SSriharsha Basavapatna 	dring_info_t		*dp;
1757bd3a2e2SSriharsha Basavapatna 
1767bd3a2e2SSriharsha Basavapatna 	dp = (dring_info_t *)kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
1777bd3a2e2SSriharsha Basavapatna 	mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
1787bd3a2e2SSriharsha Basavapatna 	ldcp->lane_out.dringp = dp;
1797bd3a2e2SSriharsha Basavapatna 
1807bd3a2e2SSriharsha Basavapatna 	/* Create the receive descriptor ring */
1817bd3a2e2SSriharsha Basavapatna 	if ((ldc_mem_dring_create(vsw_num_descriptors,
1827bd3a2e2SSriharsha Basavapatna 	    sizeof (vnet_rx_dringdata_desc_t), &dp->dring_handle)) != 0) {
1837bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_create_rx_dring(%lld): ldc dring create "
1847bd3a2e2SSriharsha Basavapatna 		    "failed", ldcp->ldc_id);
1857bd3a2e2SSriharsha Basavapatna 		goto fail;
1867bd3a2e2SSriharsha Basavapatna 	}
1877bd3a2e2SSriharsha Basavapatna 
1887bd3a2e2SSriharsha Basavapatna 	ASSERT(dp->dring_handle != NULL);
1897bd3a2e2SSriharsha Basavapatna 
1907bd3a2e2SSriharsha Basavapatna 	/* Get the addr of descriptor ring */
1917bd3a2e2SSriharsha Basavapatna 	if ((ldc_mem_dring_info(dp->dring_handle, &minfo)) != 0) {
1927bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_create_rx_dring(%lld): dring info failed\n",
1937bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id);
1947bd3a2e2SSriharsha Basavapatna 		goto fail;
1957bd3a2e2SSriharsha Basavapatna 	} else {
1967bd3a2e2SSriharsha Basavapatna 		ASSERT(minfo.vaddr != 0);
1977bd3a2e2SSriharsha Basavapatna 		dp->pub_addr = minfo.vaddr;
1987bd3a2e2SSriharsha Basavapatna 	}
1997bd3a2e2SSriharsha Basavapatna 
2007bd3a2e2SSriharsha Basavapatna 	dp->num_descriptors = vsw_num_descriptors;
2017bd3a2e2SSriharsha Basavapatna 	dp->descriptor_size = sizeof (vnet_rx_dringdata_desc_t);
2027bd3a2e2SSriharsha Basavapatna 	dp->options = VIO_RX_DRING_DATA;
2037bd3a2e2SSriharsha Basavapatna 	dp->dring_ncookies = 1;	/* guaranteed by ldc */
20434f94fbcSWENTAO YANG 	dp->num_bufs = VSW_RXDRING_NRBUFS;
2057bd3a2e2SSriharsha Basavapatna 
2067bd3a2e2SSriharsha Basavapatna 	/*
2077bd3a2e2SSriharsha Basavapatna 	 * Allocate a table that maps descriptor to its associated buffer;
2087bd3a2e2SSriharsha Basavapatna 	 * used while receiving to validate that the peer has not changed the
2097bd3a2e2SSriharsha Basavapatna 	 * buffer offset provided in the descriptor.
2107bd3a2e2SSriharsha Basavapatna 	 */
2117bd3a2e2SSriharsha Basavapatna 	dp->rxdp_to_vmp = kmem_zalloc(dp->num_descriptors * sizeof (uintptr_t),
2127bd3a2e2SSriharsha Basavapatna 	    KM_SLEEP);
2137bd3a2e2SSriharsha Basavapatna 
2147bd3a2e2SSriharsha Basavapatna 	/* Setup the descriptor ring */
2157bd3a2e2SSriharsha Basavapatna 	if (vsw_setup_rx_dring(ldcp, dp)) {
2167bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s: unable to setup ring", __func__);
2177bd3a2e2SSriharsha Basavapatna 		goto fail;
2187bd3a2e2SSriharsha Basavapatna 	}
2197bd3a2e2SSriharsha Basavapatna 
2207bd3a2e2SSriharsha Basavapatna 	/*
2217bd3a2e2SSriharsha Basavapatna 	 * The descriptors and the associated buffers are all ready;
2227bd3a2e2SSriharsha Basavapatna 	 * now bind descriptor ring to the channel.
2237bd3a2e2SSriharsha Basavapatna 	 */
2247bd3a2e2SSriharsha Basavapatna 	if ((ldc_mem_dring_bind(ldcp->ldc_handle, dp->dring_handle,
2257bd3a2e2SSriharsha Basavapatna 	    LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW,
2267bd3a2e2SSriharsha Basavapatna 	    &dp->dring_cookie[0], &dp->dring_ncookies)) != 0) {
2277bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_create_rx_dring: unable to bind to channel "
2287bd3a2e2SSriharsha Basavapatna 		    "%lld", ldcp->ldc_id);
2297bd3a2e2SSriharsha Basavapatna 		goto fail;
2307bd3a2e2SSriharsha Basavapatna 	}
2317bd3a2e2SSriharsha Basavapatna 
2327bd3a2e2SSriharsha Basavapatna 	/* haven't used any descriptors yet */
2337bd3a2e2SSriharsha Basavapatna 	dp->end_idx = 0;
2347bd3a2e2SSriharsha Basavapatna 	dp->last_ack_recv = -1;
2357bd3a2e2SSriharsha Basavapatna 	dp->next_rxi = 0;
2367bd3a2e2SSriharsha Basavapatna 	return (dp);
2377bd3a2e2SSriharsha Basavapatna 
2387bd3a2e2SSriharsha Basavapatna fail:
2397bd3a2e2SSriharsha Basavapatna 	vsw_destroy_rx_dring(ldcp);
2407bd3a2e2SSriharsha Basavapatna 	return (NULL);
2417bd3a2e2SSriharsha Basavapatna }
2427bd3a2e2SSriharsha Basavapatna 
2437bd3a2e2SSriharsha Basavapatna /*
2447bd3a2e2SSriharsha Basavapatna  * Setup the descriptors in the rx dring.
2457bd3a2e2SSriharsha Basavapatna  * Returns 0 on success, 1 on failure.
2467bd3a2e2SSriharsha Basavapatna  */
2477bd3a2e2SSriharsha Basavapatna static int
vsw_setup_rx_dring(vsw_ldc_t * ldcp,dring_info_t * dp)2487bd3a2e2SSriharsha Basavapatna vsw_setup_rx_dring(vsw_ldc_t *ldcp, dring_info_t *dp)
2497bd3a2e2SSriharsha Basavapatna {
2508e512277SWENTAO YANG 	int				i, j;
2517bd3a2e2SSriharsha Basavapatna 	int				rv;
2527bd3a2e2SSriharsha Basavapatna 	size_t				data_sz;
2537bd3a2e2SSriharsha Basavapatna 	vio_mblk_t			*vmp;
2547bd3a2e2SSriharsha Basavapatna 	vio_mblk_t			**rxdp_to_vmp;
2557bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*rxdp;
2567bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*pub_addr;
2577bd3a2e2SSriharsha Basavapatna 	vsw_t				*vswp = ldcp->ldc_vswp;
2587bd3a2e2SSriharsha Basavapatna 	uint32_t			ncookies = 0;
2597bd3a2e2SSriharsha Basavapatna 	static char			*name = "vsw_setup_rx_dring";
2607bd3a2e2SSriharsha Basavapatna 	void				*data_addr = NULL;
2617bd3a2e2SSriharsha Basavapatna 
2627bd3a2e2SSriharsha Basavapatna 	/*
2637bd3a2e2SSriharsha Basavapatna 	 * Allocate a single large buffer that serves as the rx buffer area.
2647bd3a2e2SSriharsha Basavapatna 	 * We allocate a ldc memory handle and export the buffer area as shared
2657bd3a2e2SSriharsha Basavapatna 	 * memory. We send the ldc memcookie for this buffer space to the peer,
2667bd3a2e2SSriharsha Basavapatna 	 * as part of dring registration phase during handshake. We manage this
2677bd3a2e2SSriharsha Basavapatna 	 * buffer area as individual buffers of max_frame_size and provide
2687bd3a2e2SSriharsha Basavapatna 	 * specific buffer offsets in each descriptor to the peer. Note that
2697bd3a2e2SSriharsha Basavapatna 	 * the factor used to compute the # of buffers (above) must be > 1 to
2707bd3a2e2SSriharsha Basavapatna 	 * ensure that there are more buffers than the # of descriptors. This
2717bd3a2e2SSriharsha Basavapatna 	 * is needed because, while the shared memory buffers are sent up our
2727bd3a2e2SSriharsha Basavapatna 	 * stack during receive, the sender needs additional buffers that can
2737bd3a2e2SSriharsha Basavapatna 	 * be used for further transmits. This also means there is no one to
2747bd3a2e2SSriharsha Basavapatna 	 * one correspondence between the descriptor index and buffer offset.
2757bd3a2e2SSriharsha Basavapatna 	 * The sender has to read the buffer offset in the descriptor and use
2767bd3a2e2SSriharsha Basavapatna 	 * the specified offset to copy the tx data into the shared buffer. We
2777bd3a2e2SSriharsha Basavapatna 	 * (receiver) manage the individual buffers and their state (see
2787bd3a2e2SSriharsha Basavapatna 	 * VIO_MBLK_STATEs in vio_util.h).
2797bd3a2e2SSriharsha Basavapatna 	 */
28034f94fbcSWENTAO YANG 	data_sz = RXDRING_DBLK_SZ(vswp->max_frame_size);
2817bd3a2e2SSriharsha Basavapatna 
2827bd3a2e2SSriharsha Basavapatna 	dp->desc_data_sz = data_sz;
2837bd3a2e2SSriharsha Basavapatna 	dp->data_sz = (dp->num_bufs * data_sz);
2847bd3a2e2SSriharsha Basavapatna 	data_addr = kmem_zalloc(dp->data_sz, KM_SLEEP);
2857bd3a2e2SSriharsha Basavapatna 	dp->data_addr = data_addr;
2867bd3a2e2SSriharsha Basavapatna 
2877bd3a2e2SSriharsha Basavapatna 	D2(vswp, "%s: allocated %lld bytes at 0x%llx\n", name,
2887bd3a2e2SSriharsha Basavapatna 	    dp->data_sz, dp->data_addr);
2897bd3a2e2SSriharsha Basavapatna 
2907bd3a2e2SSriharsha Basavapatna 	/* Allocate a ldc memhandle for the entire rx data area */
2917bd3a2e2SSriharsha Basavapatna 	rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &dp->data_handle);
2927bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
2937bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s: alloc mem handle failed", name);
2947bd3a2e2SSriharsha Basavapatna 		goto fail;
2957bd3a2e2SSriharsha Basavapatna 	}
2967bd3a2e2SSriharsha Basavapatna 
2977bd3a2e2SSriharsha Basavapatna 	/* Allocate memory for the data cookies */
2987bd3a2e2SSriharsha Basavapatna 	dp->data_cookie = kmem_zalloc(VNET_DATA_AREA_COOKIES *
2997bd3a2e2SSriharsha Basavapatna 	    sizeof (ldc_mem_cookie_t), KM_SLEEP);
3007bd3a2e2SSriharsha Basavapatna 
3017bd3a2e2SSriharsha Basavapatna 	/*
3027bd3a2e2SSriharsha Basavapatna 	 * Bind ldc memhandle to the corresponding rx data area.
3037bd3a2e2SSriharsha Basavapatna 	 */
3047bd3a2e2SSriharsha Basavapatna 	rv = ldc_mem_bind_handle(dp->data_handle, (caddr_t)data_addr,
3057bd3a2e2SSriharsha Basavapatna 	    dp->data_sz, LDC_DIRECT_MAP, LDC_MEM_W,
3067bd3a2e2SSriharsha Basavapatna 	    dp->data_cookie, &ncookies);
3077bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
3087bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld): ldc_mem_bind_handle failed "
3097bd3a2e2SSriharsha Basavapatna 		    "(rv %d)", name, ldcp->ldc_id, rv);
3107bd3a2e2SSriharsha Basavapatna 		goto fail;
3117bd3a2e2SSriharsha Basavapatna 	}
3127bd3a2e2SSriharsha Basavapatna 	if ((ncookies == 0) || (ncookies > VNET_DATA_AREA_COOKIES)) {
3137bd3a2e2SSriharsha Basavapatna 		goto fail;
3147bd3a2e2SSriharsha Basavapatna 	}
3157bd3a2e2SSriharsha Basavapatna 	dp->data_ncookies = ncookies;
3167bd3a2e2SSriharsha Basavapatna 
3178e512277SWENTAO YANG 	for (j = 1; j < ncookies; j++) {
3188e512277SWENTAO YANG 		rv = ldc_mem_nextcookie(dp->data_handle,
3198e512277SWENTAO YANG 		    &(dp->data_cookie[j]));
3208e512277SWENTAO YANG 		if (rv != 0) {
3218e512277SWENTAO YANG 			DERR(vswp, "%s: ldc_mem_nextcookie "
3228e512277SWENTAO YANG 			    "failed rv (%d)", name, rv);
3238e512277SWENTAO YANG 			goto fail;
3248e512277SWENTAO YANG 		}
3258e512277SWENTAO YANG 	}
3268e512277SWENTAO YANG 
3277bd3a2e2SSriharsha Basavapatna 	/*
3287bd3a2e2SSriharsha Basavapatna 	 * Successful in binding the handle to rx data area. Now setup mblks
3297bd3a2e2SSriharsha Basavapatna 	 * around each data buffer and setup the descriptors to point to these
3307bd3a2e2SSriharsha Basavapatna 	 * rx data buffers. We associate each descriptor with a buffer
3317bd3a2e2SSriharsha Basavapatna 	 * by specifying the buffer offset in the descriptor. When the peer
3327bd3a2e2SSriharsha Basavapatna 	 * needs to transmit data, this offset is read by the peer to determine
3337bd3a2e2SSriharsha Basavapatna 	 * the buffer in the mapped buffer area where the data to be
3347bd3a2e2SSriharsha Basavapatna 	 * transmitted should be copied, for a specific descriptor.
3357bd3a2e2SSriharsha Basavapatna 	 */
3367bd3a2e2SSriharsha Basavapatna 	rv = vio_create_mblks(dp->num_bufs, data_sz, (uint8_t *)data_addr,
3377bd3a2e2SSriharsha Basavapatna 	    &dp->rx_vmp);
3387bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
3397bd3a2e2SSriharsha Basavapatna 		goto fail;
3407bd3a2e2SSriharsha Basavapatna 	}
3417bd3a2e2SSriharsha Basavapatna 
3427bd3a2e2SSriharsha Basavapatna 	pub_addr = dp->pub_addr;
3437bd3a2e2SSriharsha Basavapatna 	rxdp_to_vmp = dp->rxdp_to_vmp;
3447bd3a2e2SSriharsha Basavapatna 	for (i = 0; i < dp->num_descriptors; i++) {
3457bd3a2e2SSriharsha Basavapatna 		rxdp = &pub_addr[i];
3467bd3a2e2SSriharsha Basavapatna 		/* allocate an mblk around this data buffer */
3477bd3a2e2SSriharsha Basavapatna 		vmp = vio_allocb(dp->rx_vmp);
3487bd3a2e2SSriharsha Basavapatna 		ASSERT(vmp != NULL);
3497bd3a2e2SSriharsha Basavapatna 		rxdp->data_buf_offset = VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN;
3507bd3a2e2SSriharsha Basavapatna 		rxdp->dstate = VIO_DESC_FREE;
3517bd3a2e2SSriharsha Basavapatna 		rxdp_to_vmp[i] = vmp;
3527bd3a2e2SSriharsha Basavapatna 	}
3537bd3a2e2SSriharsha Basavapatna 
3547bd3a2e2SSriharsha Basavapatna 	return (0);
3557bd3a2e2SSriharsha Basavapatna 
3567bd3a2e2SSriharsha Basavapatna fail:
3577bd3a2e2SSriharsha Basavapatna 	/* return failure; caller will cleanup */
3587bd3a2e2SSriharsha Basavapatna 	return (1);
3597bd3a2e2SSriharsha Basavapatna }
3607bd3a2e2SSriharsha Basavapatna 
3617bd3a2e2SSriharsha Basavapatna /*
3627bd3a2e2SSriharsha Basavapatna  * Free receive resources for the channel.
3637bd3a2e2SSriharsha Basavapatna  */
3647bd3a2e2SSriharsha Basavapatna void
vsw_destroy_rx_dring(vsw_ldc_t * ldcp)3657bd3a2e2SSriharsha Basavapatna vsw_destroy_rx_dring(vsw_ldc_t *ldcp)
3667bd3a2e2SSriharsha Basavapatna {
3677bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
3687bd3a2e2SSriharsha Basavapatna 	lane_t		*lp = &ldcp->lane_out;
3697bd3a2e2SSriharsha Basavapatna 	dring_info_t	*dp;
3707bd3a2e2SSriharsha Basavapatna 
3717bd3a2e2SSriharsha Basavapatna 	dp = lp->dringp;
3727bd3a2e2SSriharsha Basavapatna 	if (dp == NULL) {
3737bd3a2e2SSriharsha Basavapatna 		return;
3747bd3a2e2SSriharsha Basavapatna 	}
3757bd3a2e2SSriharsha Basavapatna 
3767bd3a2e2SSriharsha Basavapatna 	mutex_enter(&dp->dlock);
3777bd3a2e2SSriharsha Basavapatna 
3787bd3a2e2SSriharsha Basavapatna 	if (dp->rx_vmp != NULL) {
3797bd3a2e2SSriharsha Basavapatna 		vio_clobber_pool(dp->rx_vmp);
3807bd3a2e2SSriharsha Basavapatna 		/*
3817bd3a2e2SSriharsha Basavapatna 		 * If we can't destroy the rx pool for this channel, dispatch a
3827bd3a2e2SSriharsha Basavapatna 		 * task to retry and clean up those rx pools. Note that we
3837bd3a2e2SSriharsha Basavapatna 		 * don't need to wait for the task to complete. If the vsw
3847bd3a2e2SSriharsha Basavapatna 		 * device itself gets detached (vsw_detach()), it will wait for
3857bd3a2e2SSriharsha Basavapatna 		 * the task to complete implicitly in ddi_taskq_destroy().
3867bd3a2e2SSriharsha Basavapatna 		 */
3877bd3a2e2SSriharsha Basavapatna 		if (vio_destroy_mblks(dp->rx_vmp) != 0)  {
3887bd3a2e2SSriharsha Basavapatna 			(void) ddi_taskq_dispatch(vswp->rxp_taskq,
3897bd3a2e2SSriharsha Basavapatna 			    vsw_destroy_rxpools, dp->rx_vmp, DDI_SLEEP);
3907bd3a2e2SSriharsha Basavapatna 		}
3917bd3a2e2SSriharsha Basavapatna 	}
3927bd3a2e2SSriharsha Basavapatna 
3937bd3a2e2SSriharsha Basavapatna 	/* Free rx data area cookies */
3947bd3a2e2SSriharsha Basavapatna 	if (dp->data_cookie != NULL) {
3957bd3a2e2SSriharsha Basavapatna 		kmem_free(dp->data_cookie, VNET_DATA_AREA_COOKIES *
3967bd3a2e2SSriharsha Basavapatna 		    sizeof (ldc_mem_cookie_t));
3977bd3a2e2SSriharsha Basavapatna 		dp->data_cookie = NULL;
3987bd3a2e2SSriharsha Basavapatna 	}
3997bd3a2e2SSriharsha Basavapatna 
4007bd3a2e2SSriharsha Basavapatna 	/* Unbind rx data area memhandle */
4017bd3a2e2SSriharsha Basavapatna 	if (dp->data_ncookies != 0) {
4027bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_unbind_handle(dp->data_handle);
4037bd3a2e2SSriharsha Basavapatna 		dp->data_ncookies = 0;
4047bd3a2e2SSriharsha Basavapatna 	}
4057bd3a2e2SSriharsha Basavapatna 
4067bd3a2e2SSriharsha Basavapatna 	/* Free rx data area memhandle */
4077bd3a2e2SSriharsha Basavapatna 	if (dp->data_handle) {
4087bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_free_handle(dp->data_handle);
4097bd3a2e2SSriharsha Basavapatna 		dp->data_handle = 0;
4107bd3a2e2SSriharsha Basavapatna 	}
4117bd3a2e2SSriharsha Basavapatna 
4127bd3a2e2SSriharsha Basavapatna 	/* Now free the rx data area itself */
4137bd3a2e2SSriharsha Basavapatna 	if (dp->data_addr != NULL) {
4147bd3a2e2SSriharsha Basavapatna 		kmem_free(dp->data_addr, dp->data_sz);
4157bd3a2e2SSriharsha Basavapatna 	}
4167bd3a2e2SSriharsha Basavapatna 
4177bd3a2e2SSriharsha Basavapatna 	/* Finally, free the receive descriptor ring */
418*6e472272SToomas Soome 	if (dp->dring_handle != 0) {
4197bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_unbind(dp->dring_handle);
4207bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_destroy(dp->dring_handle);
4217bd3a2e2SSriharsha Basavapatna 	}
4227bd3a2e2SSriharsha Basavapatna 
4237bd3a2e2SSriharsha Basavapatna 	if (dp->rxdp_to_vmp != NULL) {
4247bd3a2e2SSriharsha Basavapatna 		kmem_free(dp->rxdp_to_vmp,
4257bd3a2e2SSriharsha Basavapatna 		    dp->num_descriptors * sizeof (uintptr_t));
4267bd3a2e2SSriharsha Basavapatna 		dp->rxdp_to_vmp = NULL;
4277bd3a2e2SSriharsha Basavapatna 	}
4287bd3a2e2SSriharsha Basavapatna 
4297bd3a2e2SSriharsha Basavapatna 	mutex_exit(&dp->dlock);
4307bd3a2e2SSriharsha Basavapatna 	mutex_destroy(&dp->dlock);
4317bd3a2e2SSriharsha Basavapatna 	mutex_destroy(&dp->restart_lock);
4327bd3a2e2SSriharsha Basavapatna 	kmem_free(dp, sizeof (dring_info_t));
4337bd3a2e2SSriharsha Basavapatna 	lp->dringp = NULL;
4347bd3a2e2SSriharsha Basavapatna }
4357bd3a2e2SSriharsha Basavapatna 
4367bd3a2e2SSriharsha Basavapatna /*
4377bd3a2e2SSriharsha Basavapatna  * Map the receive descriptor ring exported by the peer, as our transmit
4387bd3a2e2SSriharsha Basavapatna  * descriptor ring.
4397bd3a2e2SSriharsha Basavapatna  */
4407bd3a2e2SSriharsha Basavapatna dring_info_t *
vsw_map_tx_dring(vsw_ldc_t * ldcp,void * pkt)4417bd3a2e2SSriharsha Basavapatna vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt)
4427bd3a2e2SSriharsha Basavapatna {
4437bd3a2e2SSriharsha Basavapatna 	int				i;
4447bd3a2e2SSriharsha Basavapatna 	int				rv;
4457bd3a2e2SSriharsha Basavapatna 	dring_info_t			*dp;
4467bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*txdp;
4477bd3a2e2SSriharsha Basavapatna 	on_trap_data_t			otd;
4487bd3a2e2SSriharsha Basavapatna 	vio_dring_reg_msg_t		*dring_pkt = pkt;
4497bd3a2e2SSriharsha Basavapatna 
4507bd3a2e2SSriharsha Basavapatna 	dp = vsw_map_dring_cmn(ldcp, dring_pkt);
4517bd3a2e2SSriharsha Basavapatna 	if (dp == NULL) {
4527bd3a2e2SSriharsha Basavapatna 		return (NULL);
4537bd3a2e2SSriharsha Basavapatna 	}
4547bd3a2e2SSriharsha Basavapatna 
4557bd3a2e2SSriharsha Basavapatna 	/* RxDringData mode specific initializations */
4567bd3a2e2SSriharsha Basavapatna 	mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
4577bd3a2e2SSriharsha Basavapatna 	mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
4580e263307SWENTAO YANG 	dp->next_txi = dp->restart_peer_txi = 0;
4597bd3a2e2SSriharsha Basavapatna 	dp->restart_reqd = B_TRUE;
4607bd3a2e2SSriharsha Basavapatna 	ldcp->dringdata_msgid = 0;
4617bd3a2e2SSriharsha Basavapatna 	ldcp->lane_in.dringp = dp;
4627bd3a2e2SSriharsha Basavapatna 
4637bd3a2e2SSriharsha Basavapatna 	/*
4647bd3a2e2SSriharsha Basavapatna 	 * Mark the descriptor state as 'done'. This is implementation specific
4657bd3a2e2SSriharsha Basavapatna 	 * and not required by the protocol. In our implementation, we only
4667bd3a2e2SSriharsha Basavapatna 	 * need the descripor to be in 'done' state to be used by the transmit
4677bd3a2e2SSriharsha Basavapatna 	 * function and the peer is not aware of it. As the protocol requires
4687bd3a2e2SSriharsha Basavapatna 	 * that during initial registration the exporting end point mark the
4697bd3a2e2SSriharsha Basavapatna 	 * dstate as 'free', we change it 'done' here. After this, the dstate
4707bd3a2e2SSriharsha Basavapatna 	 * in our implementation will keep moving between 'ready', set by our
4717bd3a2e2SSriharsha Basavapatna 	 * transmit function; and and 'done', set by the peer (per protocol)
4727bd3a2e2SSriharsha Basavapatna 	 * after receiving data.
4737bd3a2e2SSriharsha Basavapatna 	 * Setup on_trap() protection before accessing dring shared memory area.
4747bd3a2e2SSriharsha Basavapatna 	 */
4757bd3a2e2SSriharsha Basavapatna 	rv = LDC_ON_TRAP(&otd);
4767bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
4777bd3a2e2SSriharsha Basavapatna 		/*
4787bd3a2e2SSriharsha Basavapatna 		 * Data access fault occured down the code path below while
4797bd3a2e2SSriharsha Basavapatna 		 * accessing the descriptors. Return failure.
4807bd3a2e2SSriharsha Basavapatna 		 */
4817bd3a2e2SSriharsha Basavapatna 		goto fail;
4827bd3a2e2SSriharsha Basavapatna 	}
4837bd3a2e2SSriharsha Basavapatna 
4847bd3a2e2SSriharsha Basavapatna 	txdp = (vnet_rx_dringdata_desc_t *)dp->pub_addr;
4857bd3a2e2SSriharsha Basavapatna 	for (i = 0; i < dp->num_descriptors; i++) {
4867bd3a2e2SSriharsha Basavapatna 		txdp[i].dstate = VIO_DESC_DONE;
4877bd3a2e2SSriharsha Basavapatna 	}
4887bd3a2e2SSriharsha Basavapatna 
4897bd3a2e2SSriharsha Basavapatna 	(void) LDC_NO_TRAP();
4907bd3a2e2SSriharsha Basavapatna 
4917bd3a2e2SSriharsha Basavapatna 	return (dp);
4927bd3a2e2SSriharsha Basavapatna 
4937bd3a2e2SSriharsha Basavapatna fail:
494*6e472272SToomas Soome 	if (dp->dring_handle != 0) {
4957bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_unmap(dp->dring_handle);
4967bd3a2e2SSriharsha Basavapatna 	}
4977bd3a2e2SSriharsha Basavapatna 	kmem_free(dp, sizeof (*dp));
4987bd3a2e2SSriharsha Basavapatna 	return (NULL);
4997bd3a2e2SSriharsha Basavapatna }
5007bd3a2e2SSriharsha Basavapatna 
5017bd3a2e2SSriharsha Basavapatna /*
5027bd3a2e2SSriharsha Basavapatna  * Unmap the transmit descriptor ring.
5037bd3a2e2SSriharsha Basavapatna  */
5047bd3a2e2SSriharsha Basavapatna void
vsw_unmap_tx_dring(vsw_ldc_t * ldcp)5057bd3a2e2SSriharsha Basavapatna vsw_unmap_tx_dring(vsw_ldc_t *ldcp)
5067bd3a2e2SSriharsha Basavapatna {
5077bd3a2e2SSriharsha Basavapatna 	lane_t		*lp = &ldcp->lane_in;
5087bd3a2e2SSriharsha Basavapatna 	dring_info_t	*dp;
5097bd3a2e2SSriharsha Basavapatna 
5107bd3a2e2SSriharsha Basavapatna 	if ((dp = lp->dringp) == NULL) {
5117bd3a2e2SSriharsha Basavapatna 		return;
5127bd3a2e2SSriharsha Basavapatna 	}
5137bd3a2e2SSriharsha Basavapatna 
5147bd3a2e2SSriharsha Basavapatna 	/* Unmap tx data area and free data handle */
515*6e472272SToomas Soome 	if (dp->data_handle != 0) {
5167bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_unmap(dp->data_handle);
5177bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_free_handle(dp->data_handle);
518*6e472272SToomas Soome 		dp->data_handle = 0;
5197bd3a2e2SSriharsha Basavapatna 	}
5207bd3a2e2SSriharsha Basavapatna 
5217bd3a2e2SSriharsha Basavapatna 	/* Free tx data area cookies */
5227bd3a2e2SSriharsha Basavapatna 	if (dp->data_cookie != NULL) {
5237bd3a2e2SSriharsha Basavapatna 		kmem_free(dp->data_cookie, dp->data_ncookies *
5247bd3a2e2SSriharsha Basavapatna 		    sizeof (ldc_mem_cookie_t));
5257bd3a2e2SSriharsha Basavapatna 		dp->data_cookie = NULL;
5267bd3a2e2SSriharsha Basavapatna 		dp->data_ncookies = 0;
5277bd3a2e2SSriharsha Basavapatna 	}
5287bd3a2e2SSriharsha Basavapatna 
5297bd3a2e2SSriharsha Basavapatna 	/* Unmap peer's dring */
530*6e472272SToomas Soome 	if (dp->dring_handle != 0) {
5317bd3a2e2SSriharsha Basavapatna 		(void) ldc_mem_dring_unmap(dp->dring_handle);
532*6e472272SToomas Soome 		dp->dring_handle = 0;
5337bd3a2e2SSriharsha Basavapatna 	}
5347bd3a2e2SSriharsha Basavapatna 
5357bd3a2e2SSriharsha Basavapatna 	mutex_destroy(&dp->txlock);
5367bd3a2e2SSriharsha Basavapatna 	kmem_free(dp, sizeof (dring_info_t));
5377bd3a2e2SSriharsha Basavapatna 	lp->dringp = NULL;
5387bd3a2e2SSriharsha Basavapatna }
5397bd3a2e2SSriharsha Basavapatna 
5407bd3a2e2SSriharsha Basavapatna /*
5417bd3a2e2SSriharsha Basavapatna  * A per LDC worker thread to process the rx dring and receive packets. This
5427bd3a2e2SSriharsha Basavapatna  * thread is woken up by the LDC interrupt handler when a dring data info
5437bd3a2e2SSriharsha Basavapatna  * message is received.
5447bd3a2e2SSriharsha Basavapatna  */
5457bd3a2e2SSriharsha Basavapatna void
vsw_ldc_rcv_worker(void * arg)5467bd3a2e2SSriharsha Basavapatna vsw_ldc_rcv_worker(void *arg)
5477bd3a2e2SSriharsha Basavapatna {
5487bd3a2e2SSriharsha Basavapatna 	callb_cpr_t	cprinfo;
5497bd3a2e2SSriharsha Basavapatna 	vsw_ldc_t	*ldcp = (vsw_ldc_t *)arg;
5507bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
5517bd3a2e2SSriharsha Basavapatna 
5527bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
5537bd3a2e2SSriharsha Basavapatna 	CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr,
5547bd3a2e2SSriharsha Basavapatna 	    "vsw_rcv_thread");
5557bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->rcv_thr_lock);
5567bd3a2e2SSriharsha Basavapatna 	while (!(ldcp->rcv_thr_flags & VSW_WTHR_STOP)) {
5577bd3a2e2SSriharsha Basavapatna 
5587bd3a2e2SSriharsha Basavapatna 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
5597bd3a2e2SSriharsha Basavapatna 		/*
5607bd3a2e2SSriharsha Basavapatna 		 * Wait until the data is received or a stop
5617bd3a2e2SSriharsha Basavapatna 		 * request is received.
5627bd3a2e2SSriharsha Basavapatna 		 */
5637bd3a2e2SSriharsha Basavapatna 		while (!(ldcp->rcv_thr_flags &
5647bd3a2e2SSriharsha Basavapatna 		    (VSW_WTHR_DATARCVD | VSW_WTHR_STOP))) {
5657bd3a2e2SSriharsha Basavapatna 			cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock);
5667bd3a2e2SSriharsha Basavapatna 		}
5677bd3a2e2SSriharsha Basavapatna 		CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock)
5687bd3a2e2SSriharsha Basavapatna 
5697bd3a2e2SSriharsha Basavapatna 		/*
5707bd3a2e2SSriharsha Basavapatna 		 * First process the stop request.
5717bd3a2e2SSriharsha Basavapatna 		 */
5727bd3a2e2SSriharsha Basavapatna 		if (ldcp->rcv_thr_flags & VSW_WTHR_STOP) {
5737bd3a2e2SSriharsha Basavapatna 			D2(vswp, "%s(%lld):Rx thread stopped\n",
5747bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id);
5757bd3a2e2SSriharsha Basavapatna 			break;
5767bd3a2e2SSriharsha Basavapatna 		}
5777bd3a2e2SSriharsha Basavapatna 		ldcp->rcv_thr_flags &= ~VSW_WTHR_DATARCVD;
5787bd3a2e2SSriharsha Basavapatna 		mutex_exit(&ldcp->rcv_thr_lock);
5797bd3a2e2SSriharsha Basavapatna 		D1(vswp, "%s(%lld):calling vsw_process_pkt\n",
5807bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id);
5817bd3a2e2SSriharsha Basavapatna 		vsw_ldc_rcv_shm(ldcp);
5827bd3a2e2SSriharsha Basavapatna 		mutex_enter(&ldcp->rcv_thr_lock);
5837bd3a2e2SSriharsha Basavapatna 	}
5847bd3a2e2SSriharsha Basavapatna 
5857bd3a2e2SSriharsha Basavapatna 	/*
5867bd3a2e2SSriharsha Basavapatna 	 * Update the run status and wakeup the thread that
5877bd3a2e2SSriharsha Basavapatna 	 * has sent the stop request.
5887bd3a2e2SSriharsha Basavapatna 	 */
5897bd3a2e2SSriharsha Basavapatna 	ldcp->rcv_thr_flags &= ~VSW_WTHR_STOP;
5907bd3a2e2SSriharsha Basavapatna 	ldcp->rcv_thread = NULL;
5917bd3a2e2SSriharsha Basavapatna 	CALLB_CPR_EXIT(&cprinfo);
5927bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
5937bd3a2e2SSriharsha Basavapatna 	thread_exit();
5947bd3a2e2SSriharsha Basavapatna }
5957bd3a2e2SSriharsha Basavapatna 
5967bd3a2e2SSriharsha Basavapatna /*
5977bd3a2e2SSriharsha Basavapatna  * Process the rx descriptor ring in the context of receive worker
5987bd3a2e2SSriharsha Basavapatna  * thread and switch the received packets to their destinations.
5997bd3a2e2SSriharsha Basavapatna  */
6007bd3a2e2SSriharsha Basavapatna static void
vsw_ldc_rcv_shm(vsw_ldc_t * ldcp)6017bd3a2e2SSriharsha Basavapatna vsw_ldc_rcv_shm(vsw_ldc_t *ldcp)
6027bd3a2e2SSriharsha Basavapatna {
6037bd3a2e2SSriharsha Basavapatna 	int		rv;
6047bd3a2e2SSriharsha Basavapatna 	uint32_t	end_ix;
6057bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t msg;
6067bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t	*msgp = &msg;
6077bd3a2e2SSriharsha Basavapatna 	int		count = 0;
6087bd3a2e2SSriharsha Basavapatna 	int		total_count = 0;
6097bd3a2e2SSriharsha Basavapatna 	uint32_t	retries = 0;
6107bd3a2e2SSriharsha Basavapatna 	mblk_t		*bp = NULL;
6117bd3a2e2SSriharsha Basavapatna 	mblk_t		*bpt = NULL;
6127bd3a2e2SSriharsha Basavapatna 	mblk_t		*mp = NULL;
6137bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
6147bd3a2e2SSriharsha Basavapatna 	lane_t		*lp = &ldcp->lane_out;
6157bd3a2e2SSriharsha Basavapatna 	dring_info_t	*dp = lp->dringp;
6167bd3a2e2SSriharsha Basavapatna 
6177bd3a2e2SSriharsha Basavapatna 	do {
6187bd3a2e2SSriharsha Basavapatna again:
6197bd3a2e2SSriharsha Basavapatna 		rv = vsw_receive_packet(ldcp, &mp);
6207bd3a2e2SSriharsha Basavapatna 		if (rv != 0) {
6217bd3a2e2SSriharsha Basavapatna 			if (rv == EINVAL) {
6227bd3a2e2SSriharsha Basavapatna 				/* Invalid descriptor error; get next */
6237bd3a2e2SSriharsha Basavapatna 				continue;
6247bd3a2e2SSriharsha Basavapatna 			}
6257bd3a2e2SSriharsha Basavapatna 			if (rv != EAGAIN) {
6267bd3a2e2SSriharsha Basavapatna 				break;
6277bd3a2e2SSriharsha Basavapatna 			}
6287bd3a2e2SSriharsha Basavapatna 
6297bd3a2e2SSriharsha Basavapatna 			/* Descriptor not ready for processsing */
6307bd3a2e2SSriharsha Basavapatna 			if (retries == vsw_recv_retries) {
6317bd3a2e2SSriharsha Basavapatna 				DTRACE_PROBE1(vsw_noready_rxds,
6327bd3a2e2SSriharsha Basavapatna 				    vsw_ldc_t *, ldcp);
6337bd3a2e2SSriharsha Basavapatna 				break;
6347bd3a2e2SSriharsha Basavapatna 			}
6357bd3a2e2SSriharsha Basavapatna 
6367bd3a2e2SSriharsha Basavapatna 			/* Switch packets received so far before retrying */
6377bd3a2e2SSriharsha Basavapatna 			if (bp != NULL) {
6387bd3a2e2SSriharsha Basavapatna 				VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count,
6397bd3a2e2SSriharsha Basavapatna 				    total_count);
6407bd3a2e2SSriharsha Basavapatna 			}
6417bd3a2e2SSriharsha Basavapatna 			retries++;
6427bd3a2e2SSriharsha Basavapatna 			drv_usecwait(vsw_recv_delay);
6437bd3a2e2SSriharsha Basavapatna 			goto again;
6447bd3a2e2SSriharsha Basavapatna 		}
6457bd3a2e2SSriharsha Basavapatna 		retries = 0;
6467bd3a2e2SSriharsha Basavapatna 
6477bd3a2e2SSriharsha Basavapatna 		/* Build a chain of received packets */
6487bd3a2e2SSriharsha Basavapatna 		if (bp == NULL) {
6497bd3a2e2SSriharsha Basavapatna 			/* first pkt */
6507bd3a2e2SSriharsha Basavapatna 			bp = mp;
6517bd3a2e2SSriharsha Basavapatna 			bpt = bp;
6527bd3a2e2SSriharsha Basavapatna 			bpt->b_next = NULL;
6537bd3a2e2SSriharsha Basavapatna 		} else {
6547bd3a2e2SSriharsha Basavapatna 			mp->b_next = NULL;
6557bd3a2e2SSriharsha Basavapatna 			bpt->b_next = mp;
6567bd3a2e2SSriharsha Basavapatna 			bpt = mp;
6577bd3a2e2SSriharsha Basavapatna 		}
6587bd3a2e2SSriharsha Basavapatna 
6597bd3a2e2SSriharsha Basavapatna 		total_count++;
6607bd3a2e2SSriharsha Basavapatna 		count++;
6617bd3a2e2SSriharsha Basavapatna 
6627bd3a2e2SSriharsha Basavapatna 		/*
6637bd3a2e2SSriharsha Basavapatna 		 * If we have gathered vsw_chain_len (tunable)
6647bd3a2e2SSriharsha Basavapatna 		 * # of packets in the chain, switch them.
6657bd3a2e2SSriharsha Basavapatna 		 */
6667bd3a2e2SSriharsha Basavapatna 		if (count == vsw_chain_len) {
6677bd3a2e2SSriharsha Basavapatna 			VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count,
6687bd3a2e2SSriharsha Basavapatna 			    total_count);
6697bd3a2e2SSriharsha Basavapatna 		}
6707bd3a2e2SSriharsha Basavapatna 
6717bd3a2e2SSriharsha Basavapatna 		/*
6727bd3a2e2SSriharsha Basavapatna 		 * Stop further processing if we processed the entire dring
6737bd3a2e2SSriharsha Basavapatna 		 * once; otherwise continue.
6747bd3a2e2SSriharsha Basavapatna 		 */
6757bd3a2e2SSriharsha Basavapatna 	} while (total_count < dp->num_bufs);
6767bd3a2e2SSriharsha Basavapatna 
6777bd3a2e2SSriharsha Basavapatna 	DTRACE_PROBE2(vsw_rx_total_count, vsw_ldc_t *, ldcp,
6787bd3a2e2SSriharsha Basavapatna 	    int, (total_count));
6797bd3a2e2SSriharsha Basavapatna 	if (bp != NULL) {
6807bd3a2e2SSriharsha Basavapatna 		VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count,
6817bd3a2e2SSriharsha Basavapatna 		    total_count);
6827bd3a2e2SSriharsha Basavapatna 	}
6837bd3a2e2SSriharsha Basavapatna 
6847bd3a2e2SSriharsha Basavapatna 	/* Send stopped signal to peer (sender) */
6857bd3a2e2SSriharsha Basavapatna 	end_ix = lp->dringp->next_rxi;
6867bd3a2e2SSriharsha Basavapatna 	DECR_RXI(dp, end_ix);
6877bd3a2e2SSriharsha Basavapatna 	msgp->tag.vio_msgtype = VIO_TYPE_DATA;
6887bd3a2e2SSriharsha Basavapatna 	msgp->tag.vio_subtype = VIO_SUBTYPE_ACK;
6897bd3a2e2SSriharsha Basavapatna 	msgp->tag.vio_subtype_env = VIO_DRING_DATA;
6907bd3a2e2SSriharsha Basavapatna 	msgp->dring_ident = ldcp->lane_in.dringp->ident;
6917bd3a2e2SSriharsha Basavapatna 	msgp->tag.vio_sid = ldcp->local_session;
6927bd3a2e2SSriharsha Basavapatna 	msgp->dring_process_state = VIO_DP_STOPPED;
6937bd3a2e2SSriharsha Basavapatna 	msgp->start_idx = VNET_START_IDX_UNSPEC;
6947bd3a2e2SSriharsha Basavapatna 	msgp->end_idx = end_ix;
6957bd3a2e2SSriharsha Basavapatna 
6967bd3a2e2SSriharsha Basavapatna 	(void) vsw_send_msg_shm(ldcp, (void *)msgp,
6977bd3a2e2SSriharsha Basavapatna 	    sizeof (vio_dring_msg_t), B_TRUE);
6987bd3a2e2SSriharsha Basavapatna 
6997bd3a2e2SSriharsha Basavapatna 	ldcp->ldc_stats.dring_data_acks_sent++;
7007bd3a2e2SSriharsha Basavapatna 	ldcp->ldc_stats.dring_stopped_acks_sent++;
7017bd3a2e2SSriharsha Basavapatna }
7027bd3a2e2SSriharsha Basavapatna 
7037bd3a2e2SSriharsha Basavapatna /*
7047bd3a2e2SSriharsha Basavapatna  * Process the next index in the rx dring and receive the associated packet.
7057bd3a2e2SSriharsha Basavapatna  *
7067bd3a2e2SSriharsha Basavapatna  * Returns:
7077bd3a2e2SSriharsha Basavapatna  *	bp:	Success: The received packet.
7087bd3a2e2SSriharsha Basavapatna  *		Failure: NULL
7097bd3a2e2SSriharsha Basavapatna  *      retval:
7107bd3a2e2SSriharsha Basavapatna  *		Success: 0
7117bd3a2e2SSriharsha Basavapatna  *		Failure: EAGAIN: Descriptor not ready
7127bd3a2e2SSriharsha Basavapatna  *			 EIO:    Descriptor contents invalid.
7137bd3a2e2SSriharsha Basavapatna  */
7147bd3a2e2SSriharsha Basavapatna static int
vsw_receive_packet(vsw_ldc_t * ldcp,mblk_t ** bp)7157bd3a2e2SSriharsha Basavapatna vsw_receive_packet(vsw_ldc_t *ldcp, mblk_t **bp)
7167bd3a2e2SSriharsha Basavapatna {
7177bd3a2e2SSriharsha Basavapatna 	uint32_t			rxi;
7187bd3a2e2SSriharsha Basavapatna 	vio_mblk_t			*vmp;
7197bd3a2e2SSriharsha Basavapatna 	vio_mblk_t			*new_vmp;
7207bd3a2e2SSriharsha Basavapatna 	struct ether_header		*ehp;
7217bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*rxdp;
7227bd3a2e2SSriharsha Basavapatna 	int				err = 0;
7237bd3a2e2SSriharsha Basavapatna 	uint_t				nbytes = 0;
7247bd3a2e2SSriharsha Basavapatna 	mblk_t				*mp = NULL;
7257bd3a2e2SSriharsha Basavapatna 	mblk_t				*dmp = NULL;
7267bd3a2e2SSriharsha Basavapatna 	vgen_stats_t			*statsp = &ldcp->ldc_stats;
7277bd3a2e2SSriharsha Basavapatna 	dring_info_t			*dp = ldcp->lane_out.dringp;
7287bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*pub_addr = dp->pub_addr;
7297bd3a2e2SSriharsha Basavapatna 
7307bd3a2e2SSriharsha Basavapatna 	rxi = dp->next_rxi;
7317bd3a2e2SSriharsha Basavapatna 	rxdp = &(pub_addr[rxi]);
7327bd3a2e2SSriharsha Basavapatna 	vmp = dp->rxdp_to_vmp[rxi];
7337bd3a2e2SSriharsha Basavapatna 
7347bd3a2e2SSriharsha Basavapatna 	if (rxdp->dstate != VIO_DESC_READY) {
7357bd3a2e2SSriharsha Basavapatna 		/*
7367bd3a2e2SSriharsha Basavapatna 		 * Descriptor is not ready.
7377bd3a2e2SSriharsha Basavapatna 		 */
7387bd3a2e2SSriharsha Basavapatna 		return (EAGAIN);
7397bd3a2e2SSriharsha Basavapatna 	}
7407bd3a2e2SSriharsha Basavapatna 
7417bd3a2e2SSriharsha Basavapatna 	/*
7427bd3a2e2SSriharsha Basavapatna 	 * Ensure load ordering of dstate and nbytes.
7437bd3a2e2SSriharsha Basavapatna 	 */
7447bd3a2e2SSriharsha Basavapatna 	MEMBAR_CONSUMER();
7457bd3a2e2SSriharsha Basavapatna 
7467bd3a2e2SSriharsha Basavapatna 	if ((rxdp->nbytes < ETHERMIN) ||
7477bd3a2e2SSriharsha Basavapatna 	    (rxdp->nbytes > ldcp->lane_in.mtu) ||
7487bd3a2e2SSriharsha Basavapatna 	    (rxdp->data_buf_offset !=
7497bd3a2e2SSriharsha Basavapatna 	    (VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN))) {
7507bd3a2e2SSriharsha Basavapatna 		/*
7517bd3a2e2SSriharsha Basavapatna 		 * Descriptor contents invalid.
7527bd3a2e2SSriharsha Basavapatna 		 */
7537bd3a2e2SSriharsha Basavapatna 		statsp->ierrors++;
7547bd3a2e2SSriharsha Basavapatna 		rxdp->dstate = VIO_DESC_DONE;
7557bd3a2e2SSriharsha Basavapatna 		err = EIO;
7567bd3a2e2SSriharsha Basavapatna 		goto done;
7577bd3a2e2SSriharsha Basavapatna 	}
7587bd3a2e2SSriharsha Basavapatna 
7597bd3a2e2SSriharsha Basavapatna 	/*
7607bd3a2e2SSriharsha Basavapatna 	 * Now allocate a new buffer for this descriptor before sending up the
7617bd3a2e2SSriharsha Basavapatna 	 * buffer being processed. If that fails, stop processing; as we are
7627bd3a2e2SSriharsha Basavapatna 	 * out of receive buffers.
7637bd3a2e2SSriharsha Basavapatna 	 */
7647bd3a2e2SSriharsha Basavapatna 	new_vmp = vio_allocb(dp->rx_vmp);
7657bd3a2e2SSriharsha Basavapatna 
7667bd3a2e2SSriharsha Basavapatna 	/*
7677bd3a2e2SSriharsha Basavapatna 	 * Process the current buffer being received.
7687bd3a2e2SSriharsha Basavapatna 	 */
7697bd3a2e2SSriharsha Basavapatna 	nbytes = rxdp->nbytes;
7707bd3a2e2SSriharsha Basavapatna 	mp = vmp->mp;
7717bd3a2e2SSriharsha Basavapatna 
7727bd3a2e2SSriharsha Basavapatna 	if (new_vmp == NULL) {
7737bd3a2e2SSriharsha Basavapatna 		/*
7747bd3a2e2SSriharsha Basavapatna 		 * We failed to get a new mapped buffer that is needed to
7757bd3a2e2SSriharsha Basavapatna 		 * refill the descriptor. In that case, leave the current
7767bd3a2e2SSriharsha Basavapatna 		 * buffer bound to the descriptor; allocate an mblk dynamically
7777bd3a2e2SSriharsha Basavapatna 		 * and copy the contents of the buffer to the mblk. Then send
7787bd3a2e2SSriharsha Basavapatna 		 * up this mblk. This way the sender has the same buffer as
7797bd3a2e2SSriharsha Basavapatna 		 * before that can be used to send new data.
7807bd3a2e2SSriharsha Basavapatna 		 */
7817bd3a2e2SSriharsha Basavapatna 		statsp->norcvbuf++;
7827bd3a2e2SSriharsha Basavapatna 		dmp = allocb(nbytes + VNET_IPALIGN, BPRI_MED);
7837bd3a2e2SSriharsha Basavapatna 		bcopy(mp->b_rptr + VNET_IPALIGN,
7847bd3a2e2SSriharsha Basavapatna 		    dmp->b_rptr + VNET_IPALIGN, nbytes);
7857bd3a2e2SSriharsha Basavapatna 		mp = dmp;
7867bd3a2e2SSriharsha Basavapatna 	} else {
7877bd3a2e2SSriharsha Basavapatna 		/* Mark the status of the current rbuf */
7887bd3a2e2SSriharsha Basavapatna 		vmp->state = VIO_MBLK_HAS_DATA;
7897bd3a2e2SSriharsha Basavapatna 
7907bd3a2e2SSriharsha Basavapatna 		/* Set the offset of the new buffer in the descriptor */
7917bd3a2e2SSriharsha Basavapatna 		rxdp->data_buf_offset =
7927bd3a2e2SSriharsha Basavapatna 		    VIO_MBLK_DATA_OFF(new_vmp) + VNET_IPALIGN;
7937bd3a2e2SSriharsha Basavapatna 		dp->rxdp_to_vmp[rxi] = new_vmp;
7947bd3a2e2SSriharsha Basavapatna 	}
7957bd3a2e2SSriharsha Basavapatna 	mp->b_rptr += VNET_IPALIGN;
7967bd3a2e2SSriharsha Basavapatna 	mp->b_wptr = mp->b_rptr + nbytes;
7977bd3a2e2SSriharsha Basavapatna 
7987bd3a2e2SSriharsha Basavapatna 	/*
7997bd3a2e2SSriharsha Basavapatna 	 * Ensure store ordering of data_buf_offset and dstate; so that the
8007bd3a2e2SSriharsha Basavapatna 	 * peer sees the right data_buf_offset after it checks that the dstate
8017bd3a2e2SSriharsha Basavapatna 	 * is DONE.
8027bd3a2e2SSriharsha Basavapatna 	 */
8037bd3a2e2SSriharsha Basavapatna 	MEMBAR_PRODUCER();
8047bd3a2e2SSriharsha Basavapatna 
8057bd3a2e2SSriharsha Basavapatna 	/* Now mark the descriptor 'done' */
8067bd3a2e2SSriharsha Basavapatna 	rxdp->dstate = VIO_DESC_DONE;
8077bd3a2e2SSriharsha Basavapatna 
8087bd3a2e2SSriharsha Basavapatna 	/* Update stats */
8097bd3a2e2SSriharsha Basavapatna 	statsp->ipackets++;
8107bd3a2e2SSriharsha Basavapatna 	statsp->rbytes += rxdp->nbytes;
8117bd3a2e2SSriharsha Basavapatna 	ehp = (struct ether_header *)mp->b_rptr;
8127bd3a2e2SSriharsha Basavapatna 	if (IS_BROADCAST(ehp))
8137bd3a2e2SSriharsha Basavapatna 		statsp->brdcstrcv++;
8147bd3a2e2SSriharsha Basavapatna 	else if (IS_MULTICAST(ehp))
8157bd3a2e2SSriharsha Basavapatna 		statsp->multircv++;
8167bd3a2e2SSriharsha Basavapatna done:
8177bd3a2e2SSriharsha Basavapatna 	/* Update the next index to be processed */
8187bd3a2e2SSriharsha Basavapatna 	INCR_RXI(dp, rxi);
8197bd3a2e2SSriharsha Basavapatna 
8207bd3a2e2SSriharsha Basavapatna 	/* Save the new recv index */
8217bd3a2e2SSriharsha Basavapatna 	dp->next_rxi = rxi;
8227bd3a2e2SSriharsha Basavapatna 
8237bd3a2e2SSriharsha Basavapatna 	/* Return the packet received */
8247bd3a2e2SSriharsha Basavapatna 	*bp = mp;
8257bd3a2e2SSriharsha Basavapatna 	return (err);
8267bd3a2e2SSriharsha Basavapatna }
8277bd3a2e2SSriharsha Basavapatna 
8287bd3a2e2SSriharsha Basavapatna void
vsw_stop_rcv_thread(vsw_ldc_t * ldcp)8297bd3a2e2SSriharsha Basavapatna vsw_stop_rcv_thread(vsw_ldc_t *ldcp)
8307bd3a2e2SSriharsha Basavapatna {
8317bd3a2e2SSriharsha Basavapatna 	kt_did_t	tid = 0;
8327bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
8337bd3a2e2SSriharsha Basavapatna 
8347bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
8357bd3a2e2SSriharsha Basavapatna 	/*
8367bd3a2e2SSriharsha Basavapatna 	 * Send a stop request by setting the stop flag and
8377bd3a2e2SSriharsha Basavapatna 	 * wait until the rcv process thread stops.
8387bd3a2e2SSriharsha Basavapatna 	 */
8397bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->rcv_thr_lock);
8407bd3a2e2SSriharsha Basavapatna 	if (ldcp->rcv_thread != NULL) {
8417bd3a2e2SSriharsha Basavapatna 		tid = ldcp->rcv_thread->t_did;
8427bd3a2e2SSriharsha Basavapatna 		ldcp->rcv_thr_flags |= VSW_WTHR_STOP;
8437bd3a2e2SSriharsha Basavapatna 		cv_signal(&ldcp->rcv_thr_cv);
8447bd3a2e2SSriharsha Basavapatna 	}
8457bd3a2e2SSriharsha Basavapatna 	mutex_exit(&ldcp->rcv_thr_lock);
8467bd3a2e2SSriharsha Basavapatna 
8477bd3a2e2SSriharsha Basavapatna 	if (tid != 0) {
8487bd3a2e2SSriharsha Basavapatna 		thread_join(tid);
8497bd3a2e2SSriharsha Basavapatna 	}
8507bd3a2e2SSriharsha Basavapatna 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
8517bd3a2e2SSriharsha Basavapatna }
8527bd3a2e2SSriharsha Basavapatna 
8537bd3a2e2SSriharsha Basavapatna int
vsw_dringsend_shm(vsw_ldc_t * ldcp,mblk_t * mp)8547bd3a2e2SSriharsha Basavapatna vsw_dringsend_shm(vsw_ldc_t *ldcp, mblk_t *mp)
8557bd3a2e2SSriharsha Basavapatna {
8567bd3a2e2SSriharsha Basavapatna 	uint32_t			next_txi;
8577bd3a2e2SSriharsha Basavapatna 	uint32_t			txi;
8587bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*txdp;
8597bd3a2e2SSriharsha Basavapatna 	struct ether_header		*ehp;
8607bd3a2e2SSriharsha Basavapatna 	size_t				mblksz;
8617bd3a2e2SSriharsha Basavapatna 	caddr_t				dst;
8627bd3a2e2SSriharsha Basavapatna 	mblk_t				*bp;
8637bd3a2e2SSriharsha Basavapatna 	size_t				size;
8647bd3a2e2SSriharsha Basavapatna 	on_trap_data_t			otd;
8657bd3a2e2SSriharsha Basavapatna 	uint32_t			buf_offset;
8667bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*pub_addr;
8677bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t			msg;
8687bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t			*msgp = &msg;
8697bd3a2e2SSriharsha Basavapatna 	int				rv = 0;
8707bd3a2e2SSriharsha Basavapatna 	boolean_t			resched_peer = B_FALSE;
8717bd3a2e2SSriharsha Basavapatna 	boolean_t			is_bcast = B_FALSE;
8727bd3a2e2SSriharsha Basavapatna 	boolean_t			is_mcast = B_FALSE;
8737bd3a2e2SSriharsha Basavapatna 	vgen_stats_t			*statsp = &ldcp->ldc_stats;
8747bd3a2e2SSriharsha Basavapatna 	lane_t				*lane_in = &ldcp->lane_in;
8757bd3a2e2SSriharsha Basavapatna 	lane_t				*lane_out = &ldcp->lane_out;
8767bd3a2e2SSriharsha Basavapatna 	dring_info_t			*dp = lane_in->dringp;
8777bd3a2e2SSriharsha Basavapatna 	vsw_t				*vswp = ldcp->ldc_vswp;
8787bd3a2e2SSriharsha Basavapatna 
8797bd3a2e2SSriharsha Basavapatna 	if ((!(lane_in->lstate & VSW_LANE_ACTIVE)) ||
880*6e472272SToomas Soome 	    (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == 0)) {
8817bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
8827bd3a2e2SSriharsha Basavapatna 		    "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
8837bd3a2e2SSriharsha Basavapatna 		    lane_in->lstate);
8847bd3a2e2SSriharsha Basavapatna 		statsp->oerrors++;
8857bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_FAILURE);
8867bd3a2e2SSriharsha Basavapatna 	}
8877bd3a2e2SSriharsha Basavapatna 
8887bd3a2e2SSriharsha Basavapatna 	if (dp == NULL) {
8897bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld): no dring for outbound lane on"
8907bd3a2e2SSriharsha Basavapatna 		    " channel %d", __func__, ldcp->ldc_id, ldcp->ldc_id);
8917bd3a2e2SSriharsha Basavapatna 		statsp->oerrors++;
8927bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_FAILURE);
8937bd3a2e2SSriharsha Basavapatna 	}
8947bd3a2e2SSriharsha Basavapatna 	pub_addr = dp->pub_addr;
8957bd3a2e2SSriharsha Basavapatna 
8967bd3a2e2SSriharsha Basavapatna 	size = msgsize(mp);
8977bd3a2e2SSriharsha Basavapatna 
8987bd3a2e2SSriharsha Basavapatna 	/*
8997bd3a2e2SSriharsha Basavapatna 	 * Note: In RxDringData mode, lane_in is associated with transmit and
9007bd3a2e2SSriharsha Basavapatna 	 * lane_out is associated with receive. However, we still keep the
9017bd3a2e2SSriharsha Basavapatna 	 * negotiated mtu in lane_out (our exported attributes).
9027bd3a2e2SSriharsha Basavapatna 	 */
9037bd3a2e2SSriharsha Basavapatna 	if (size > (size_t)lane_out->mtu) {
9047bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
9057bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, size);
9067bd3a2e2SSriharsha Basavapatna 		statsp->oerrors++;
9077bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_FAILURE);
9087bd3a2e2SSriharsha Basavapatna 	}
9097bd3a2e2SSriharsha Basavapatna 
9107bd3a2e2SSriharsha Basavapatna 	if (size < ETHERMIN)
9117bd3a2e2SSriharsha Basavapatna 		size = ETHERMIN;
9127bd3a2e2SSriharsha Basavapatna 
9137bd3a2e2SSriharsha Basavapatna 	ehp = (struct ether_header *)mp->b_rptr;
9147bd3a2e2SSriharsha Basavapatna 	is_bcast = IS_BROADCAST(ehp);
9157bd3a2e2SSriharsha Basavapatna 	is_mcast = IS_MULTICAST(ehp);
9167bd3a2e2SSriharsha Basavapatna 
9177bd3a2e2SSriharsha Basavapatna 	/*
9187bd3a2e2SSriharsha Basavapatna 	 * Setup on_trap() protection before accessing shared memory areas
9197bd3a2e2SSriharsha Basavapatna 	 * (descriptor and data buffer). Note that we enable this protection a
9207bd3a2e2SSriharsha Basavapatna 	 * little early and turn it off slightly later, than keeping it enabled
9217bd3a2e2SSriharsha Basavapatna 	 * strictly at the points in code below where the descriptor and data
9227bd3a2e2SSriharsha Basavapatna 	 * buffer are accessed. This is done for performance reasons:
9237bd3a2e2SSriharsha Basavapatna 	 * (a) to avoid calling the trap protection code while holding mutex.
9247bd3a2e2SSriharsha Basavapatna 	 * (b) to avoid multiple on/off steps for descriptor and data accesses.
9257bd3a2e2SSriharsha Basavapatna 	 */
9267bd3a2e2SSriharsha Basavapatna 	rv = LDC_ON_TRAP(&otd);
9277bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
9287bd3a2e2SSriharsha Basavapatna 		/*
9297bd3a2e2SSriharsha Basavapatna 		 * Data access fault occured down the code path below while
9307bd3a2e2SSriharsha Basavapatna 		 * accessing either the descriptor or the data buffer. Release
9317bd3a2e2SSriharsha Basavapatna 		 * any locks that we might have acquired in the code below and
9327bd3a2e2SSriharsha Basavapatna 		 * return failure.
9337bd3a2e2SSriharsha Basavapatna 		 */
9347bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld) data access fault occured\n",
9357bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id);
9367bd3a2e2SSriharsha Basavapatna 		statsp->oerrors++;
9377bd3a2e2SSriharsha Basavapatna 		if (mutex_owned(&dp->txlock)) {
9387bd3a2e2SSriharsha Basavapatna 			mutex_exit(&dp->txlock);
9397bd3a2e2SSriharsha Basavapatna 		}
9407bd3a2e2SSriharsha Basavapatna 		if (mutex_owned(&dp->restart_lock)) {
9417bd3a2e2SSriharsha Basavapatna 			mutex_exit(&dp->restart_lock);
9427bd3a2e2SSriharsha Basavapatna 		}
9437bd3a2e2SSriharsha Basavapatna 		goto dringsend_shm_exit;
9447bd3a2e2SSriharsha Basavapatna 	}
9457bd3a2e2SSriharsha Basavapatna 
9467bd3a2e2SSriharsha Basavapatna 	/*
9477bd3a2e2SSriharsha Basavapatna 	 * Allocate a descriptor
9487bd3a2e2SSriharsha Basavapatna 	 */
9497bd3a2e2SSriharsha Basavapatna 	mutex_enter(&dp->txlock);
9507bd3a2e2SSriharsha Basavapatna 	txi = next_txi = dp->next_txi;
9517bd3a2e2SSriharsha Basavapatna 	INCR_TXI(dp, next_txi);
9520e263307SWENTAO YANG 	txdp = &(pub_addr[txi]);
9530e263307SWENTAO YANG 	if (txdp->dstate != VIO_DESC_DONE) { /* out of descriptors */
9547bd3a2e2SSriharsha Basavapatna 		statsp->tx_no_desc++;
9557bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->txlock);
9567bd3a2e2SSriharsha Basavapatna 		(void) LDC_NO_TRAP();
9577bd3a2e2SSriharsha Basavapatna 		return (LDC_TX_NORESOURCES);
9580e263307SWENTAO YANG 	} else {
9590e263307SWENTAO YANG 		txdp->dstate = VIO_DESC_INITIALIZING;
9607bd3a2e2SSriharsha Basavapatna 	}
9617bd3a2e2SSriharsha Basavapatna 
9627bd3a2e2SSriharsha Basavapatna 	/* Update descriptor ring index */
9637bd3a2e2SSriharsha Basavapatna 	dp->next_txi = next_txi;
9647bd3a2e2SSriharsha Basavapatna 	mutex_exit(&dp->txlock);
9657bd3a2e2SSriharsha Basavapatna 
9667bd3a2e2SSriharsha Basavapatna 	/* Ensure load ordering of dstate (above) and data_buf_offset. */
9677bd3a2e2SSriharsha Basavapatna 	MEMBAR_CONSUMER();
9687bd3a2e2SSriharsha Basavapatna 
9697bd3a2e2SSriharsha Basavapatna 	/* Get the offset of the buffer to be used */
9707bd3a2e2SSriharsha Basavapatna 	buf_offset = txdp->data_buf_offset;
9717bd3a2e2SSriharsha Basavapatna 
9727bd3a2e2SSriharsha Basavapatna 	/* Access the buffer using the offset */
9737bd3a2e2SSriharsha Basavapatna 	dst = (caddr_t)dp->data_addr + buf_offset;
9747bd3a2e2SSriharsha Basavapatna 
9757bd3a2e2SSriharsha Basavapatna 	/* Copy data into mapped transmit buffer */
9767bd3a2e2SSriharsha Basavapatna 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
9777bd3a2e2SSriharsha Basavapatna 		mblksz = MBLKL(bp);
9787bd3a2e2SSriharsha Basavapatna 		bcopy(bp->b_rptr, dst, mblksz);
9797bd3a2e2SSriharsha Basavapatna 		dst += mblksz;
9807bd3a2e2SSriharsha Basavapatna 	}
9817bd3a2e2SSriharsha Basavapatna 
9827bd3a2e2SSriharsha Basavapatna 	/* Set the size of data in the descriptor */
9837bd3a2e2SSriharsha Basavapatna 	txdp->nbytes = size;
9847bd3a2e2SSriharsha Basavapatna 
9857bd3a2e2SSriharsha Basavapatna 	/*
9867bd3a2e2SSriharsha Basavapatna 	 * Ensure store ordering of nbytes and dstate (below); so that the peer
9877bd3a2e2SSriharsha Basavapatna 	 * sees the right nbytes value after it checks that the dstate is READY.
9887bd3a2e2SSriharsha Basavapatna 	 */
9897bd3a2e2SSriharsha Basavapatna 	MEMBAR_PRODUCER();
9907bd3a2e2SSriharsha Basavapatna 
9917bd3a2e2SSriharsha Basavapatna 	mutex_enter(&dp->restart_lock);
9927bd3a2e2SSriharsha Basavapatna 
9930e263307SWENTAO YANG 	ASSERT(txdp->dstate == VIO_DESC_INITIALIZING);
9940e263307SWENTAO YANG 
9957bd3a2e2SSriharsha Basavapatna 	/* Mark the descriptor ready */
9967bd3a2e2SSriharsha Basavapatna 	txdp->dstate = VIO_DESC_READY;
9977bd3a2e2SSriharsha Basavapatna 
9987bd3a2e2SSriharsha Basavapatna 	/* Check if peer needs wake up (handled below) */
9990e263307SWENTAO YANG 	if (dp->restart_reqd == B_TRUE && dp->restart_peer_txi == txi) {
10007bd3a2e2SSriharsha Basavapatna 		dp->restart_reqd = B_FALSE;
10017bd3a2e2SSriharsha Basavapatna 		resched_peer = B_TRUE;
10027bd3a2e2SSriharsha Basavapatna 	}
10037bd3a2e2SSriharsha Basavapatna 
10047bd3a2e2SSriharsha Basavapatna 	/* Update tx stats */
10057bd3a2e2SSriharsha Basavapatna 	statsp->opackets++;
10067bd3a2e2SSriharsha Basavapatna 	statsp->obytes += size;
10077bd3a2e2SSriharsha Basavapatna 	if (is_bcast)
10087bd3a2e2SSriharsha Basavapatna 		statsp->brdcstxmt++;
10097bd3a2e2SSriharsha Basavapatna 	else if (is_mcast)
10107bd3a2e2SSriharsha Basavapatna 		statsp->multixmt++;
10117bd3a2e2SSriharsha Basavapatna 
10127bd3a2e2SSriharsha Basavapatna 	mutex_exit(&dp->restart_lock);
10137bd3a2e2SSriharsha Basavapatna 
10147bd3a2e2SSriharsha Basavapatna 	/*
10157bd3a2e2SSriharsha Basavapatna 	 * We are done accessing shared memory; clear trap protection.
10167bd3a2e2SSriharsha Basavapatna 	 */
10177bd3a2e2SSriharsha Basavapatna 	(void) LDC_NO_TRAP();
10187bd3a2e2SSriharsha Basavapatna 
10197bd3a2e2SSriharsha Basavapatna 	/*
10207bd3a2e2SSriharsha Basavapatna 	 * Need to wake up the peer ?
10217bd3a2e2SSriharsha Basavapatna 	 */
10227bd3a2e2SSriharsha Basavapatna 	if (resched_peer == B_TRUE) {
10237bd3a2e2SSriharsha Basavapatna 		msgp->tag.vio_msgtype = VIO_TYPE_DATA;
10247bd3a2e2SSriharsha Basavapatna 		msgp->tag.vio_subtype = VIO_SUBTYPE_INFO;
10257bd3a2e2SSriharsha Basavapatna 		msgp->tag.vio_subtype_env = VIO_DRING_DATA;
10267bd3a2e2SSriharsha Basavapatna 		msgp->tag.vio_sid = ldcp->local_session;
10277bd3a2e2SSriharsha Basavapatna 		msgp->dring_ident = lane_out->dringp->ident;
10287bd3a2e2SSriharsha Basavapatna 		msgp->start_idx = txi;
10297bd3a2e2SSriharsha Basavapatna 		msgp->end_idx = -1;
10307bd3a2e2SSriharsha Basavapatna 
10317bd3a2e2SSriharsha Basavapatna 		rv = vsw_send_msg_shm(ldcp, (void *)msgp, sizeof (*msgp),
10327bd3a2e2SSriharsha Basavapatna 		    B_FALSE);
10337bd3a2e2SSriharsha Basavapatna 		if (rv != 0) {
10347bd3a2e2SSriharsha Basavapatna 			/* error: drop the packet */
10357bd3a2e2SSriharsha Basavapatna 			DERR(vswp, "%s(%lld) failed sending dringdata msg\n",
10367bd3a2e2SSriharsha Basavapatna 			    __func__, ldcp->ldc_id);
10377bd3a2e2SSriharsha Basavapatna 			mutex_enter(&dp->restart_lock);
10387bd3a2e2SSriharsha Basavapatna 			statsp->oerrors++;
10397bd3a2e2SSriharsha Basavapatna 			dp->restart_reqd = B_TRUE;
10407bd3a2e2SSriharsha Basavapatna 			mutex_exit(&dp->restart_lock);
10417bd3a2e2SSriharsha Basavapatna 		}
10427bd3a2e2SSriharsha Basavapatna 		statsp->dring_data_msgs_sent++;
10437bd3a2e2SSriharsha Basavapatna 	}
10447bd3a2e2SSriharsha Basavapatna 
10457bd3a2e2SSriharsha Basavapatna dringsend_shm_exit:
10467bd3a2e2SSriharsha Basavapatna 	if (rv == ECONNRESET || rv == EACCES) {
10477bd3a2e2SSriharsha Basavapatna 		vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
10487bd3a2e2SSriharsha Basavapatna 	}
10497bd3a2e2SSriharsha Basavapatna 	return (LDC_TX_SUCCESS);
10507bd3a2e2SSriharsha Basavapatna }
10517bd3a2e2SSriharsha Basavapatna 
10527bd3a2e2SSriharsha Basavapatna void
vsw_process_dringdata_shm(void * arg,void * dpkt)10537bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_shm(void *arg, void *dpkt)
10547bd3a2e2SSriharsha Basavapatna {
10557bd3a2e2SSriharsha Basavapatna 	vsw_ldc_t		*ldcp = arg;
10567bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
10577bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t		*dring_pkt = dpkt;
10587bd3a2e2SSriharsha Basavapatna 
10597bd3a2e2SSriharsha Basavapatna 	switch (dring_pkt->tag.vio_subtype) {
10607bd3a2e2SSriharsha Basavapatna 	case VIO_SUBTYPE_INFO:
10617bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): VIO_SUBTYPE_INFO", __func__, ldcp->ldc_id);
10627bd3a2e2SSriharsha Basavapatna 		vsw_process_dringdata_info_shm(ldcp, dring_pkt);
10637bd3a2e2SSriharsha Basavapatna 		break;
10647bd3a2e2SSriharsha Basavapatna 
10657bd3a2e2SSriharsha Basavapatna 	case VIO_SUBTYPE_ACK:
10667bd3a2e2SSriharsha Basavapatna 		D2(vswp, "%s(%lld): VIO_SUBTYPE_ACK", __func__, ldcp->ldc_id);
10677bd3a2e2SSriharsha Basavapatna 		vsw_process_dringdata_ack_shm(ldcp, dring_pkt);
10687bd3a2e2SSriharsha Basavapatna 		break;
10697bd3a2e2SSriharsha Basavapatna 
10707bd3a2e2SSriharsha Basavapatna 	case VIO_SUBTYPE_NACK:
10717bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s(%lld): VIO_SUBTYPE_NACK",
10727bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id);
10737bd3a2e2SSriharsha Basavapatna 		/*
10747bd3a2e2SSriharsha Basavapatna 		 * Something is badly wrong if we are getting NACK's
10757bd3a2e2SSriharsha Basavapatna 		 * for our data pkts. So reset the channel.
10767bd3a2e2SSriharsha Basavapatna 		 */
10777bd3a2e2SSriharsha Basavapatna 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
10787bd3a2e2SSriharsha Basavapatna 		break;
10797bd3a2e2SSriharsha Basavapatna 
10807bd3a2e2SSriharsha Basavapatna 	default:
10817bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
10827bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, dring_pkt->tag.vio_subtype);
10837bd3a2e2SSriharsha Basavapatna 	}
10847bd3a2e2SSriharsha Basavapatna }
10857bd3a2e2SSriharsha Basavapatna 
10867bd3a2e2SSriharsha Basavapatna static void
vsw_process_dringdata_info_shm(vsw_ldc_t * ldcp,vio_dring_msg_t * msg)10877bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_info_shm(vsw_ldc_t *ldcp, vio_dring_msg_t *msg)
10887bd3a2e2SSriharsha Basavapatna {
10897bd3a2e2SSriharsha Basavapatna 	dring_info_t	*dp = ldcp->lane_in.dringp;
10907bd3a2e2SSriharsha Basavapatna 	vsw_t		*vswp = ldcp->ldc_vswp;
10917bd3a2e2SSriharsha Basavapatna 	vgen_stats_t	*statsp = &ldcp->ldc_stats;
10927bd3a2e2SSriharsha Basavapatna 
10937bd3a2e2SSriharsha Basavapatna 	if (dp->ident != msg->dring_ident) {
10947bd3a2e2SSriharsha Basavapatna 		/* drop the message */
10957bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "%s(%lld): Invalid dring ident 0x%llx",
10967bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id, msg->dring_ident);
10977bd3a2e2SSriharsha Basavapatna 		return;
10987bd3a2e2SSriharsha Basavapatna 	}
10997bd3a2e2SSriharsha Basavapatna 
11007bd3a2e2SSriharsha Basavapatna 	statsp->dring_data_msgs_rcvd++;
11017bd3a2e2SSriharsha Basavapatna 
11027bd3a2e2SSriharsha Basavapatna 	/*
11037bd3a2e2SSriharsha Basavapatna 	 * Wake up the rcv worker thread to process the rx dring.
11047bd3a2e2SSriharsha Basavapatna 	 */
11057bd3a2e2SSriharsha Basavapatna 	ASSERT(MUTEX_HELD(&ldcp->ldc_cblock));
11067bd3a2e2SSriharsha Basavapatna 	mutex_exit(&ldcp->ldc_cblock);
11077bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->rcv_thr_lock);
11087bd3a2e2SSriharsha Basavapatna 	if (!(ldcp->rcv_thr_flags & VSW_WTHR_DATARCVD)) {
11097bd3a2e2SSriharsha Basavapatna 		ldcp->rcv_thr_flags |= VSW_WTHR_DATARCVD;
11107bd3a2e2SSriharsha Basavapatna 		cv_signal(&ldcp->rcv_thr_cv);
11117bd3a2e2SSriharsha Basavapatna 	}
11127bd3a2e2SSriharsha Basavapatna 	mutex_exit(&ldcp->rcv_thr_lock);
11137bd3a2e2SSriharsha Basavapatna 	mutex_enter(&ldcp->ldc_cblock);
11147bd3a2e2SSriharsha Basavapatna }
11157bd3a2e2SSriharsha Basavapatna 
11167bd3a2e2SSriharsha Basavapatna static void
vsw_process_dringdata_ack_shm(vsw_ldc_t * ldcp,vio_dring_msg_t * msg)11177bd3a2e2SSriharsha Basavapatna vsw_process_dringdata_ack_shm(vsw_ldc_t *ldcp, vio_dring_msg_t *msg)
11187bd3a2e2SSriharsha Basavapatna {
11197bd3a2e2SSriharsha Basavapatna 	dring_info_t			*dp;
11207bd3a2e2SSriharsha Basavapatna 	uint32_t			start;
11217bd3a2e2SSriharsha Basavapatna 	int32_t				end;
11227bd3a2e2SSriharsha Basavapatna 	int				rv;
11237bd3a2e2SSriharsha Basavapatna 	on_trap_data_t			otd;
11247bd3a2e2SSriharsha Basavapatna 	uint32_t			txi;
11257bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*txdp;
11267bd3a2e2SSriharsha Basavapatna 	vnet_rx_dringdata_desc_t	*pub_addr;
11277bd3a2e2SSriharsha Basavapatna 	boolean_t			ready_txd = B_FALSE;
11287bd3a2e2SSriharsha Basavapatna 	vsw_t				*vswp = ldcp->ldc_vswp;
11297bd3a2e2SSriharsha Basavapatna 	vgen_stats_t			*statsp = &ldcp->ldc_stats;
11307bd3a2e2SSriharsha Basavapatna 
11317bd3a2e2SSriharsha Basavapatna 	dp = ldcp->lane_in.dringp;
11327bd3a2e2SSriharsha Basavapatna 	start = msg->start_idx;
11337bd3a2e2SSriharsha Basavapatna 	end = msg->end_idx;
11347bd3a2e2SSriharsha Basavapatna 	pub_addr = dp->pub_addr;
11357bd3a2e2SSriharsha Basavapatna 
11367bd3a2e2SSriharsha Basavapatna 	/*
11377bd3a2e2SSriharsha Basavapatna 	 * In RxDringData mode (v1.6), start index of -1 can be used by the
11387bd3a2e2SSriharsha Basavapatna 	 * peer to indicate that it is unspecified. However, the end index
11397bd3a2e2SSriharsha Basavapatna 	 * must be set correctly indicating the last descriptor index processed.
11407bd3a2e2SSriharsha Basavapatna 	 */
11417bd3a2e2SSriharsha Basavapatna 	if (((start != VNET_START_IDX_UNSPEC) && !(CHECK_TXI(dp, start))) ||
11427bd3a2e2SSriharsha Basavapatna 	    !(CHECK_TXI(dp, end))) {
11437bd3a2e2SSriharsha Basavapatna 		/* drop the message if invalid index */
11447bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s(%lld): Invalid Tx ack start(%d) or end(%d)\n",
11457bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id, start, end);
11467bd3a2e2SSriharsha Basavapatna 		return;
11477bd3a2e2SSriharsha Basavapatna 	}
11487bd3a2e2SSriharsha Basavapatna 
11497bd3a2e2SSriharsha Basavapatna 	/* Validate dring_ident */
11507bd3a2e2SSriharsha Basavapatna 	if (msg->dring_ident != ldcp->lane_out.dringp->ident) {
11517bd3a2e2SSriharsha Basavapatna 		/* invalid dring_ident, drop the msg */
11527bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s(%lld): Invalid dring ident 0x%x\n",
11537bd3a2e2SSriharsha Basavapatna 		    __func__, ldcp->ldc_id, msg->dring_ident);
11547bd3a2e2SSriharsha Basavapatna 		return;
11557bd3a2e2SSriharsha Basavapatna 	}
11567bd3a2e2SSriharsha Basavapatna 	statsp->dring_data_acks_rcvd++;
11577bd3a2e2SSriharsha Basavapatna 
11587bd3a2e2SSriharsha Basavapatna 	if (msg->dring_process_state != VIO_DP_STOPPED) {
11597bd3a2e2SSriharsha Basavapatna 		/*
11607bd3a2e2SSriharsha Basavapatna 		 * Receiver continued processing
11617bd3a2e2SSriharsha Basavapatna 		 * dring after sending us the ack.
11627bd3a2e2SSriharsha Basavapatna 		 */
11637bd3a2e2SSriharsha Basavapatna 		return;
11647bd3a2e2SSriharsha Basavapatna 	}
11657bd3a2e2SSriharsha Basavapatna 
11667bd3a2e2SSriharsha Basavapatna 	statsp->dring_stopped_acks_rcvd++;
11677bd3a2e2SSriharsha Basavapatna 
11687bd3a2e2SSriharsha Basavapatna 	/*
11697bd3a2e2SSriharsha Basavapatna 	 * Setup on_trap() protection before accessing dring shared memory area.
11707bd3a2e2SSriharsha Basavapatna 	 */
11717bd3a2e2SSriharsha Basavapatna 	rv = LDC_ON_TRAP(&otd);
11727bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
11737bd3a2e2SSriharsha Basavapatna 		/*
11747bd3a2e2SSriharsha Basavapatna 		 * Data access fault occured down the code path below while
11757bd3a2e2SSriharsha Basavapatna 		 * accessing the descriptors. Release any locks that we might
11767bd3a2e2SSriharsha Basavapatna 		 * have acquired in the code below and return failure.
11777bd3a2e2SSriharsha Basavapatna 		 */
11787bd3a2e2SSriharsha Basavapatna 		if (mutex_owned(&dp->restart_lock)) {
11797bd3a2e2SSriharsha Basavapatna 			mutex_exit(&dp->restart_lock);
11807bd3a2e2SSriharsha Basavapatna 		}
11817bd3a2e2SSriharsha Basavapatna 		return;
11827bd3a2e2SSriharsha Basavapatna 	}
11837bd3a2e2SSriharsha Basavapatna 
11847bd3a2e2SSriharsha Basavapatna 	/*
11857bd3a2e2SSriharsha Basavapatna 	 * Determine if there are any pending tx descriptors ready to be
11867bd3a2e2SSriharsha Basavapatna 	 * processed by the receiver(peer) and if so, send a message to the
11877bd3a2e2SSriharsha Basavapatna 	 * peer to restart receiving.
11887bd3a2e2SSriharsha Basavapatna 	 */
11897bd3a2e2SSriharsha Basavapatna 	mutex_enter(&dp->restart_lock);
11907bd3a2e2SSriharsha Basavapatna 
11917bd3a2e2SSriharsha Basavapatna 	ready_txd = B_FALSE;
11927bd3a2e2SSriharsha Basavapatna 	txi = end;
11937bd3a2e2SSriharsha Basavapatna 	INCR_TXI(dp, txi);
11947bd3a2e2SSriharsha Basavapatna 	txdp = &pub_addr[txi];
11957bd3a2e2SSriharsha Basavapatna 	if (txdp->dstate == VIO_DESC_READY) {
11967bd3a2e2SSriharsha Basavapatna 		ready_txd = B_TRUE;
11977bd3a2e2SSriharsha Basavapatna 	}
11987bd3a2e2SSriharsha Basavapatna 
11997bd3a2e2SSriharsha Basavapatna 	/*
12007bd3a2e2SSriharsha Basavapatna 	 * We are done accessing shared memory; clear trap protection.
12017bd3a2e2SSriharsha Basavapatna 	 */
12027bd3a2e2SSriharsha Basavapatna 	(void) LDC_NO_TRAP();
12037bd3a2e2SSriharsha Basavapatna 
12047bd3a2e2SSriharsha Basavapatna 	if (ready_txd == B_FALSE) {
12057bd3a2e2SSriharsha Basavapatna 		/*
12067bd3a2e2SSriharsha Basavapatna 		 * No ready tx descriptors. Set the flag to send a message to
12077bd3a2e2SSriharsha Basavapatna 		 * the peer when tx descriptors are ready in transmit routine.
12087bd3a2e2SSriharsha Basavapatna 		 */
12097bd3a2e2SSriharsha Basavapatna 		dp->restart_reqd = B_TRUE;
12100e263307SWENTAO YANG 		dp->restart_peer_txi = txi;
12117bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->restart_lock);
12127bd3a2e2SSriharsha Basavapatna 		return;
12137bd3a2e2SSriharsha Basavapatna 	}
12147bd3a2e2SSriharsha Basavapatna 
12157bd3a2e2SSriharsha Basavapatna 	/*
12167bd3a2e2SSriharsha Basavapatna 	 * We have some tx descriptors ready to be processed by the receiver.
12177bd3a2e2SSriharsha Basavapatna 	 * Send a dring data message to the peer to restart processing.
12187bd3a2e2SSriharsha Basavapatna 	 */
12197bd3a2e2SSriharsha Basavapatna 	dp->restart_reqd = B_FALSE;
12207bd3a2e2SSriharsha Basavapatna 	mutex_exit(&dp->restart_lock);
12217bd3a2e2SSriharsha Basavapatna 
12227bd3a2e2SSriharsha Basavapatna 	msg->tag.vio_msgtype = VIO_TYPE_DATA;
12237bd3a2e2SSriharsha Basavapatna 	msg->tag.vio_subtype = VIO_SUBTYPE_INFO;
12247bd3a2e2SSriharsha Basavapatna 	msg->tag.vio_subtype_env = VIO_DRING_DATA;
12257bd3a2e2SSriharsha Basavapatna 	msg->tag.vio_sid = ldcp->local_session;
12267bd3a2e2SSriharsha Basavapatna 	msg->dring_ident = ldcp->lane_out.dringp->ident;
12277bd3a2e2SSriharsha Basavapatna 	msg->start_idx = txi;
12287bd3a2e2SSriharsha Basavapatna 	msg->end_idx = -1;
12297bd3a2e2SSriharsha Basavapatna 	rv = vsw_send_msg_shm(ldcp, (void *)msg,
12307bd3a2e2SSriharsha Basavapatna 	    sizeof (vio_dring_msg_t), B_FALSE);
12317bd3a2e2SSriharsha Basavapatna 	statsp->dring_data_msgs_sent++;
12327bd3a2e2SSriharsha Basavapatna 	if (rv != 0) {
12337bd3a2e2SSriharsha Basavapatna 		mutex_enter(&dp->restart_lock);
12347bd3a2e2SSriharsha Basavapatna 		dp->restart_reqd = B_TRUE;
12357bd3a2e2SSriharsha Basavapatna 		mutex_exit(&dp->restart_lock);
12367bd3a2e2SSriharsha Basavapatna 	}
12377bd3a2e2SSriharsha Basavapatna 
12387bd3a2e2SSriharsha Basavapatna 	if (rv == ECONNRESET) {
12397bd3a2e2SSriharsha Basavapatna 		vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
12407bd3a2e2SSriharsha Basavapatna 	}
12417bd3a2e2SSriharsha Basavapatna }
12427bd3a2e2SSriharsha Basavapatna 
12437bd3a2e2SSriharsha Basavapatna /*
12447bd3a2e2SSriharsha Basavapatna  * Send dring data msgs (info/ack/nack) over LDC.
12457bd3a2e2SSriharsha Basavapatna  */
12467bd3a2e2SSriharsha Basavapatna int
vsw_send_msg_shm(vsw_ldc_t * ldcp,void * msgp,int size,boolean_t handle_reset)12477bd3a2e2SSriharsha Basavapatna vsw_send_msg_shm(vsw_ldc_t *ldcp, void *msgp, int size, boolean_t handle_reset)
12487bd3a2e2SSriharsha Basavapatna {
12497bd3a2e2SSriharsha Basavapatna 	int			rv;
12507bd3a2e2SSriharsha Basavapatna 	int			retries = vsw_wretries;
12517bd3a2e2SSriharsha Basavapatna 	size_t			msglen = size;
12527bd3a2e2SSriharsha Basavapatna 	vsw_t			*vswp = ldcp->ldc_vswp;
12537bd3a2e2SSriharsha Basavapatna 	vio_dring_msg_t		*dmsg = (vio_dring_msg_t *)msgp;
12547bd3a2e2SSriharsha Basavapatna 
12557bd3a2e2SSriharsha Basavapatna 	D1(vswp, "vsw_send_msg (%lld) enter : sending %d bytes",
12567bd3a2e2SSriharsha Basavapatna 	    ldcp->ldc_id, size);
12577bd3a2e2SSriharsha Basavapatna 
12587bd3a2e2SSriharsha Basavapatna 	dmsg->seq_num = atomic_inc_32_nv(&ldcp->dringdata_msgid);
12597bd3a2e2SSriharsha Basavapatna 
12607bd3a2e2SSriharsha Basavapatna 	do {
12617bd3a2e2SSriharsha Basavapatna 		msglen = size;
12627bd3a2e2SSriharsha Basavapatna 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msgp, &msglen);
12637bd3a2e2SSriharsha Basavapatna 	} while (rv == EWOULDBLOCK && --retries > 0);
12647bd3a2e2SSriharsha Basavapatna 
12657bd3a2e2SSriharsha Basavapatna 	if ((rv != 0) || (msglen != size)) {
12667bd3a2e2SSriharsha Basavapatna 		DERR(vswp, "vsw_send_msg_shm:ldc_write failed: "
12677bd3a2e2SSriharsha Basavapatna 		    "chan(%lld) rv(%d) size (%d) msglen(%d)\n",
12687bd3a2e2SSriharsha Basavapatna 		    ldcp->ldc_id, rv, size, msglen);
12697bd3a2e2SSriharsha Basavapatna 		ldcp->ldc_stats.oerrors++;
12707bd3a2e2SSriharsha Basavapatna 	}
12717bd3a2e2SSriharsha Basavapatna 
12727bd3a2e2SSriharsha Basavapatna 	/*
12737bd3a2e2SSriharsha Basavapatna 	 * If channel has been reset we either handle it here or
12747bd3a2e2SSriharsha Basavapatna 	 * simply report back that it has been reset and let caller
12757bd3a2e2SSriharsha Basavapatna 	 * decide what to do.
12767bd3a2e2SSriharsha Basavapatna 	 */
12777bd3a2e2SSriharsha Basavapatna 	if (rv == ECONNRESET) {
12787bd3a2e2SSriharsha Basavapatna 		DWARN(vswp, "%s (%lld) channel reset", __func__, ldcp->ldc_id);
12797bd3a2e2SSriharsha Basavapatna 
12807bd3a2e2SSriharsha Basavapatna 		if (handle_reset) {
12817bd3a2e2SSriharsha Basavapatna 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
12827bd3a2e2SSriharsha Basavapatna 		}
12837bd3a2e2SSriharsha Basavapatna 	}
12847bd3a2e2SSriharsha Basavapatna 
12857bd3a2e2SSriharsha Basavapatna 	return (rv);
12867bd3a2e2SSriharsha Basavapatna }
1287