xref: /onnv-gate/usr/src/uts/sun4v/io/vsw_rxdring.c (revision 13098:496fd9979cfc)
112011SSriharsha.Basavapatna@Sun.COM /*
212011SSriharsha.Basavapatna@Sun.COM  * CDDL HEADER START
312011SSriharsha.Basavapatna@Sun.COM  *
412011SSriharsha.Basavapatna@Sun.COM  * The contents of this file are subject to the terms of the
512011SSriharsha.Basavapatna@Sun.COM  * Common Development and Distribution License (the "License").
612011SSriharsha.Basavapatna@Sun.COM  * You may not use this file except in compliance with the License.
712011SSriharsha.Basavapatna@Sun.COM  *
812011SSriharsha.Basavapatna@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
912011SSriharsha.Basavapatna@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1012011SSriharsha.Basavapatna@Sun.COM  * See the License for the specific language governing permissions
1112011SSriharsha.Basavapatna@Sun.COM  * and limitations under the License.
1212011SSriharsha.Basavapatna@Sun.COM  *
1312011SSriharsha.Basavapatna@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1412011SSriharsha.Basavapatna@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1512011SSriharsha.Basavapatna@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1612011SSriharsha.Basavapatna@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1712011SSriharsha.Basavapatna@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1812011SSriharsha.Basavapatna@Sun.COM  *
1912011SSriharsha.Basavapatna@Sun.COM  * CDDL HEADER END
2012011SSriharsha.Basavapatna@Sun.COM  */
2112011SSriharsha.Basavapatna@Sun.COM 
2212011SSriharsha.Basavapatna@Sun.COM /*
2312642SWentao.Yang@Sun.COM  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2412011SSriharsha.Basavapatna@Sun.COM  */
2512642SWentao.Yang@Sun.COM 
2612011SSriharsha.Basavapatna@Sun.COM #include <sys/types.h>
2712011SSriharsha.Basavapatna@Sun.COM #include <sys/errno.h>
2812011SSriharsha.Basavapatna@Sun.COM #include <sys/sysmacros.h>
2912011SSriharsha.Basavapatna@Sun.COM #include <sys/param.h>
3012011SSriharsha.Basavapatna@Sun.COM #include <sys/machsystm.h>
3112011SSriharsha.Basavapatna@Sun.COM #include <sys/stream.h>
3212011SSriharsha.Basavapatna@Sun.COM #include <sys/strsubr.h>
3312011SSriharsha.Basavapatna@Sun.COM #include <sys/kmem.h>
3412011SSriharsha.Basavapatna@Sun.COM #include <sys/strsun.h>
3512011SSriharsha.Basavapatna@Sun.COM #include <sys/callb.h>
3612011SSriharsha.Basavapatna@Sun.COM #include <sys/sdt.h>
3712011SSriharsha.Basavapatna@Sun.COM #include <sys/mach_descrip.h>
3812011SSriharsha.Basavapatna@Sun.COM #include <sys/mdeg.h>
3912011SSriharsha.Basavapatna@Sun.COM #include <net/if.h>
4012011SSriharsha.Basavapatna@Sun.COM #include <sys/vsw.h>
4112011SSriharsha.Basavapatna@Sun.COM #include <sys/vio_mailbox.h>
4212011SSriharsha.Basavapatna@Sun.COM #include <sys/vio_common.h>
4312011SSriharsha.Basavapatna@Sun.COM #include <sys/vnet_common.h>
4412011SSriharsha.Basavapatna@Sun.COM #include <sys/vnet_mailbox.h>
4512011SSriharsha.Basavapatna@Sun.COM #include <sys/vio_util.h>
4612011SSriharsha.Basavapatna@Sun.COM 
4712011SSriharsha.Basavapatna@Sun.COM /*
4812011SSriharsha.Basavapatna@Sun.COM  * This file contains the implementation of RxDringData transfer mode of VIO
4912011SSriharsha.Basavapatna@Sun.COM  * Protocol in vsw. The functions in this file are invoked from vsw_ldc.c
5012011SSriharsha.Basavapatna@Sun.COM  * after RxDringData mode is negotiated with the peer during attribute phase of
5112011SSriharsha.Basavapatna@Sun.COM  * handshake. This file contains functions that setup the transmit and receive
5212011SSriharsha.Basavapatna@Sun.COM  * descriptor rings, and associated resources in RxDringData mode. It also
5312011SSriharsha.Basavapatna@Sun.COM  * contains the transmit and receive data processing functions that are invoked
5412011SSriharsha.Basavapatna@Sun.COM  * in RxDringData mode. The data processing routines in this file have the
5512011SSriharsha.Basavapatna@Sun.COM  * suffix '_shm' to indicate the shared memory mechanism used in RxDringData
5612011SSriharsha.Basavapatna@Sun.COM  * mode.
5712011SSriharsha.Basavapatna@Sun.COM  */
5812011SSriharsha.Basavapatna@Sun.COM 
5912011SSriharsha.Basavapatna@Sun.COM /* Functions exported to vsw_ldc.c */
6012011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_msg_t *vsw_create_rx_dring_info(vsw_ldc_t *);
6112011SSriharsha.Basavapatna@Sun.COM void vsw_destroy_rx_dring(vsw_ldc_t *ldcp);
6212011SSriharsha.Basavapatna@Sun.COM dring_info_t *vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt);
6312011SSriharsha.Basavapatna@Sun.COM void vsw_unmap_tx_dring(vsw_ldc_t *ldcp);
6412011SSriharsha.Basavapatna@Sun.COM int vsw_dringsend_shm(vsw_ldc_t *, mblk_t *);
6512011SSriharsha.Basavapatna@Sun.COM void vsw_ldc_rcv_worker(void *arg);
6612011SSriharsha.Basavapatna@Sun.COM void vsw_stop_rcv_thread(vsw_ldc_t *ldcp);
6712011SSriharsha.Basavapatna@Sun.COM void vsw_process_dringdata_shm(void *, void *);
6812011SSriharsha.Basavapatna@Sun.COM 
6912011SSriharsha.Basavapatna@Sun.COM /* Internal functions */
7012011SSriharsha.Basavapatna@Sun.COM static dring_info_t *vsw_create_rx_dring(vsw_ldc_t *);
7112011SSriharsha.Basavapatna@Sun.COM static int vsw_setup_rx_dring(vsw_ldc_t *ldcp, dring_info_t *dp);
7212011SSriharsha.Basavapatna@Sun.COM static void vsw_process_dringdata_info_shm(vsw_ldc_t *ldcp,
7312011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t *msg);
7412011SSriharsha.Basavapatna@Sun.COM static void vsw_process_dringdata_ack_shm(vsw_ldc_t *ldcp,
7512011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t *msg);
7612011SSriharsha.Basavapatna@Sun.COM static void vsw_ldc_rcv_shm(vsw_ldc_t *ldcp);
7712011SSriharsha.Basavapatna@Sun.COM static int vsw_receive_packet(vsw_ldc_t *ldcp, mblk_t **bp);
7812011SSriharsha.Basavapatna@Sun.COM static int vsw_send_msg_shm(vsw_ldc_t *ldcp, void *msgp, int size,
7912011SSriharsha.Basavapatna@Sun.COM     boolean_t handle_reset);
8012011SSriharsha.Basavapatna@Sun.COM 
8112011SSriharsha.Basavapatna@Sun.COM /* Functions imported from vsw_ldc.c */
8212011SSriharsha.Basavapatna@Sun.COM extern void vsw_process_pkt(void *);
8312011SSriharsha.Basavapatna@Sun.COM extern void vsw_destroy_rxpools(void *);
8412011SSriharsha.Basavapatna@Sun.COM extern dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp,
8512011SSriharsha.Basavapatna@Sun.COM     vio_dring_reg_msg_t *dring_pkt);
8612011SSriharsha.Basavapatna@Sun.COM extern void vsw_process_conn_evt(vsw_ldc_t *, uint16_t);
8712011SSriharsha.Basavapatna@Sun.COM extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
8812011SSriharsha.Basavapatna@Sun.COM 
8912011SSriharsha.Basavapatna@Sun.COM /* Tunables */
9012011SSriharsha.Basavapatna@Sun.COM extern int vsw_wretries;
9112011SSriharsha.Basavapatna@Sun.COM extern int vsw_recv_delay;
9212011SSriharsha.Basavapatna@Sun.COM extern int vsw_recv_retries;
9312011SSriharsha.Basavapatna@Sun.COM extern uint32_t vsw_chain_len;
9412011SSriharsha.Basavapatna@Sun.COM extern uint32_t vsw_num_descriptors;
9512011SSriharsha.Basavapatna@Sun.COM extern uint32_t vsw_nrbufs_factor;
9612011SSriharsha.Basavapatna@Sun.COM 
9712011SSriharsha.Basavapatna@Sun.COM #define	VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count, total_count)	\
9812011SSriharsha.Basavapatna@Sun.COM {									\
9912011SSriharsha.Basavapatna@Sun.COM 	DTRACE_PROBE2(vsw_rx_pkts, vsw_ldc_t *, (ldcp), int, (count));	\
10012011SSriharsha.Basavapatna@Sun.COM 	(vswp)->vsw_switch_frame((vswp), (bp), VSW_VNETPORT,		\
10112011SSriharsha.Basavapatna@Sun.COM 	    (ldcp)->ldc_port, NULL);					\
10212011SSriharsha.Basavapatna@Sun.COM 	(bp) = (bpt) = NULL;						\
10312011SSriharsha.Basavapatna@Sun.COM 	(count) = 0;							\
10412011SSriharsha.Basavapatna@Sun.COM }
10512011SSriharsha.Basavapatna@Sun.COM 
10612011SSriharsha.Basavapatna@Sun.COM vio_dring_reg_msg_t *
vsw_create_rx_dring_info(vsw_ldc_t * ldcp)10712011SSriharsha.Basavapatna@Sun.COM vsw_create_rx_dring_info(vsw_ldc_t *ldcp)
10812011SSriharsha.Basavapatna@Sun.COM {
10912011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_msg_t	*mp;
11012011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_ext_msg_t	*emsg;
11112011SSriharsha.Basavapatna@Sun.COM 	dring_info_t		*dp;
11212011SSriharsha.Basavapatna@Sun.COM 	uint8_t			*buf;
11312011SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
11412011SSriharsha.Basavapatna@Sun.COM 
11512011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s enter\n", __func__);
11612011SSriharsha.Basavapatna@Sun.COM 
11712011SSriharsha.Basavapatna@Sun.COM 	/*
11812011SSriharsha.Basavapatna@Sun.COM 	 * If we can't create a dring, obviously no point sending
11912011SSriharsha.Basavapatna@Sun.COM 	 * a message.
12012011SSriharsha.Basavapatna@Sun.COM 	 */
12112011SSriharsha.Basavapatna@Sun.COM 	if ((dp = vsw_create_rx_dring(ldcp)) == NULL)
12212011SSriharsha.Basavapatna@Sun.COM 		return (NULL);
12312011SSriharsha.Basavapatna@Sun.COM 
12412011SSriharsha.Basavapatna@Sun.COM 	mp = kmem_zalloc(VNET_DRING_REG_EXT_MSG_SIZE(dp->data_ncookies),
12512011SSriharsha.Basavapatna@Sun.COM 	    KM_SLEEP);
12612011SSriharsha.Basavapatna@Sun.COM 
12712011SSriharsha.Basavapatna@Sun.COM 	mp->tag.vio_msgtype = VIO_TYPE_CTRL;
12812011SSriharsha.Basavapatna@Sun.COM 	mp->tag.vio_subtype = VIO_SUBTYPE_INFO;
12912011SSriharsha.Basavapatna@Sun.COM 	mp->tag.vio_subtype_env = VIO_DRING_REG;
13012011SSriharsha.Basavapatna@Sun.COM 	mp->tag.vio_sid = ldcp->local_session;
13112011SSriharsha.Basavapatna@Sun.COM 
13212011SSriharsha.Basavapatna@Sun.COM 	/* payload */
13312011SSriharsha.Basavapatna@Sun.COM 	mp->num_descriptors = dp->num_descriptors;
13412011SSriharsha.Basavapatna@Sun.COM 	mp->descriptor_size = dp->descriptor_size;
13512011SSriharsha.Basavapatna@Sun.COM 	mp->options = dp->options;
13612011SSriharsha.Basavapatna@Sun.COM 	mp->ncookies = dp->dring_ncookies;
13712011SSriharsha.Basavapatna@Sun.COM 	bcopy(&dp->dring_cookie[0], &mp->cookie[0],
13812011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t));
13912011SSriharsha.Basavapatna@Sun.COM 
14012011SSriharsha.Basavapatna@Sun.COM 	mp->dring_ident = 0;
14112011SSriharsha.Basavapatna@Sun.COM 
14212011SSriharsha.Basavapatna@Sun.COM 	buf = (uint8_t *)mp->cookie;
14312011SSriharsha.Basavapatna@Sun.COM 
14412011SSriharsha.Basavapatna@Sun.COM 	/* skip over dring cookies */
14512011SSriharsha.Basavapatna@Sun.COM 	ASSERT(mp->ncookies == 1);
14612011SSriharsha.Basavapatna@Sun.COM 	buf += (mp->ncookies * sizeof (ldc_mem_cookie_t));
14712011SSriharsha.Basavapatna@Sun.COM 
14812011SSriharsha.Basavapatna@Sun.COM 	emsg = (vio_dring_reg_ext_msg_t *)buf;
14912011SSriharsha.Basavapatna@Sun.COM 
15012011SSriharsha.Basavapatna@Sun.COM 	/* copy data_ncookies in the msg */
15112011SSriharsha.Basavapatna@Sun.COM 	emsg->data_ncookies = dp->data_ncookies;
15212011SSriharsha.Basavapatna@Sun.COM 
15312011SSriharsha.Basavapatna@Sun.COM 	/* copy data area size in the msg */
15412011SSriharsha.Basavapatna@Sun.COM 	emsg->data_area_size = dp->data_sz;
15512011SSriharsha.Basavapatna@Sun.COM 
15612011SSriharsha.Basavapatna@Sun.COM 	/* copy data area cookies in the msg */
15712011SSriharsha.Basavapatna@Sun.COM 	bcopy(dp->data_cookie, (ldc_mem_cookie_t *)emsg->data_cookie,
15812011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t) * dp->data_ncookies);
15912011SSriharsha.Basavapatna@Sun.COM 
16012011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s exit\n", __func__);
16112011SSriharsha.Basavapatna@Sun.COM 
16212011SSriharsha.Basavapatna@Sun.COM 	return (mp);
16312011SSriharsha.Basavapatna@Sun.COM }
16412011SSriharsha.Basavapatna@Sun.COM 
16512011SSriharsha.Basavapatna@Sun.COM /*
16612011SSriharsha.Basavapatna@Sun.COM  * Allocate receive resources for the channel. The resources consist of a
16712011SSriharsha.Basavapatna@Sun.COM  * receive descriptor ring and an associated receive buffer area.
16812011SSriharsha.Basavapatna@Sun.COM  */
16912011SSriharsha.Basavapatna@Sun.COM static dring_info_t *
vsw_create_rx_dring(vsw_ldc_t * ldcp)17012011SSriharsha.Basavapatna@Sun.COM vsw_create_rx_dring(vsw_ldc_t *ldcp)
17112011SSriharsha.Basavapatna@Sun.COM {
17212011SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
17312011SSriharsha.Basavapatna@Sun.COM 	ldc_mem_info_t		minfo;
17412011SSriharsha.Basavapatna@Sun.COM 	dring_info_t		*dp;
17512011SSriharsha.Basavapatna@Sun.COM 
17612011SSriharsha.Basavapatna@Sun.COM 	dp = (dring_info_t *)kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
17712011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL);
17812011SSriharsha.Basavapatna@Sun.COM 	ldcp->lane_out.dringp = dp;
17912011SSriharsha.Basavapatna@Sun.COM 
18012011SSriharsha.Basavapatna@Sun.COM 	/* Create the receive descriptor ring */
18112011SSriharsha.Basavapatna@Sun.COM 	if ((ldc_mem_dring_create(vsw_num_descriptors,
18212011SSriharsha.Basavapatna@Sun.COM 	    sizeof (vnet_rx_dringdata_desc_t), &dp->dring_handle)) != 0) {
18312011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "vsw_create_rx_dring(%lld): ldc dring create "
18412011SSriharsha.Basavapatna@Sun.COM 		    "failed", ldcp->ldc_id);
18512011SSriharsha.Basavapatna@Sun.COM 		goto fail;
18612011SSriharsha.Basavapatna@Sun.COM 	}
18712011SSriharsha.Basavapatna@Sun.COM 
18812011SSriharsha.Basavapatna@Sun.COM 	ASSERT(dp->dring_handle != NULL);
18912011SSriharsha.Basavapatna@Sun.COM 
19012011SSriharsha.Basavapatna@Sun.COM 	/* Get the addr of descriptor ring */
19112011SSriharsha.Basavapatna@Sun.COM 	if ((ldc_mem_dring_info(dp->dring_handle, &minfo)) != 0) {
19212011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "vsw_create_rx_dring(%lld): dring info failed\n",
19312011SSriharsha.Basavapatna@Sun.COM 		    ldcp->ldc_id);
19412011SSriharsha.Basavapatna@Sun.COM 		goto fail;
19512011SSriharsha.Basavapatna@Sun.COM 	} else {
19612011SSriharsha.Basavapatna@Sun.COM 		ASSERT(minfo.vaddr != 0);
19712011SSriharsha.Basavapatna@Sun.COM 		dp->pub_addr = minfo.vaddr;
19812011SSriharsha.Basavapatna@Sun.COM 	}
19912011SSriharsha.Basavapatna@Sun.COM 
20012011SSriharsha.Basavapatna@Sun.COM 	dp->num_descriptors = vsw_num_descriptors;
20112011SSriharsha.Basavapatna@Sun.COM 	dp->descriptor_size = sizeof (vnet_rx_dringdata_desc_t);
20212011SSriharsha.Basavapatna@Sun.COM 	dp->options = VIO_RX_DRING_DATA;
20312011SSriharsha.Basavapatna@Sun.COM 	dp->dring_ncookies = 1;	/* guaranteed by ldc */
204*13098SWentao.Yang@Sun.COM 	dp->num_bufs = VSW_RXDRING_NRBUFS;
20512011SSriharsha.Basavapatna@Sun.COM 
20612011SSriharsha.Basavapatna@Sun.COM 	/*
20712011SSriharsha.Basavapatna@Sun.COM 	 * Allocate a table that maps descriptor to its associated buffer;
20812011SSriharsha.Basavapatna@Sun.COM 	 * used while receiving to validate that the peer has not changed the
20912011SSriharsha.Basavapatna@Sun.COM 	 * buffer offset provided in the descriptor.
21012011SSriharsha.Basavapatna@Sun.COM 	 */
21112011SSriharsha.Basavapatna@Sun.COM 	dp->rxdp_to_vmp = kmem_zalloc(dp->num_descriptors * sizeof (uintptr_t),
21212011SSriharsha.Basavapatna@Sun.COM 	    KM_SLEEP);
21312011SSriharsha.Basavapatna@Sun.COM 
21412011SSriharsha.Basavapatna@Sun.COM 	/* Setup the descriptor ring */
21512011SSriharsha.Basavapatna@Sun.COM 	if (vsw_setup_rx_dring(ldcp, dp)) {
21612011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s: unable to setup ring", __func__);
21712011SSriharsha.Basavapatna@Sun.COM 		goto fail;
21812011SSriharsha.Basavapatna@Sun.COM 	}
21912011SSriharsha.Basavapatna@Sun.COM 
22012011SSriharsha.Basavapatna@Sun.COM 	/*
22112011SSriharsha.Basavapatna@Sun.COM 	 * The descriptors and the associated buffers are all ready;
22212011SSriharsha.Basavapatna@Sun.COM 	 * now bind descriptor ring to the channel.
22312011SSriharsha.Basavapatna@Sun.COM 	 */
22412011SSriharsha.Basavapatna@Sun.COM 	if ((ldc_mem_dring_bind(ldcp->ldc_handle, dp->dring_handle,
22512011SSriharsha.Basavapatna@Sun.COM 	    LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW,
22612011SSriharsha.Basavapatna@Sun.COM 	    &dp->dring_cookie[0], &dp->dring_ncookies)) != 0) {
22712011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "vsw_create_rx_dring: unable to bind to channel "
22812011SSriharsha.Basavapatna@Sun.COM 		    "%lld", ldcp->ldc_id);
22912011SSriharsha.Basavapatna@Sun.COM 		goto fail;
23012011SSriharsha.Basavapatna@Sun.COM 	}
23112011SSriharsha.Basavapatna@Sun.COM 
23212011SSriharsha.Basavapatna@Sun.COM 	/* haven't used any descriptors yet */
23312011SSriharsha.Basavapatna@Sun.COM 	dp->end_idx = 0;
23412011SSriharsha.Basavapatna@Sun.COM 	dp->last_ack_recv = -1;
23512011SSriharsha.Basavapatna@Sun.COM 	dp->next_rxi = 0;
23612011SSriharsha.Basavapatna@Sun.COM 	return (dp);
23712011SSriharsha.Basavapatna@Sun.COM 
23812011SSriharsha.Basavapatna@Sun.COM fail:
23912011SSriharsha.Basavapatna@Sun.COM 	vsw_destroy_rx_dring(ldcp);
24012011SSriharsha.Basavapatna@Sun.COM 	return (NULL);
24112011SSriharsha.Basavapatna@Sun.COM }
24212011SSriharsha.Basavapatna@Sun.COM 
24312011SSriharsha.Basavapatna@Sun.COM /*
24412011SSriharsha.Basavapatna@Sun.COM  * Setup the descriptors in the rx dring.
24512011SSriharsha.Basavapatna@Sun.COM  * Returns 0 on success, 1 on failure.
24612011SSriharsha.Basavapatna@Sun.COM  */
24712011SSriharsha.Basavapatna@Sun.COM static int
vsw_setup_rx_dring(vsw_ldc_t * ldcp,dring_info_t * dp)24812011SSriharsha.Basavapatna@Sun.COM vsw_setup_rx_dring(vsw_ldc_t *ldcp, dring_info_t *dp)
24912011SSriharsha.Basavapatna@Sun.COM {
25012642SWentao.Yang@Sun.COM 	int				i, j;
25112011SSriharsha.Basavapatna@Sun.COM 	int				rv;
25212011SSriharsha.Basavapatna@Sun.COM 	size_t				data_sz;
25312011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			*vmp;
25412011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			**rxdp_to_vmp;
25512011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*rxdp;
25612011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*pub_addr;
25712011SSriharsha.Basavapatna@Sun.COM 	vsw_t				*vswp = ldcp->ldc_vswp;
25812011SSriharsha.Basavapatna@Sun.COM 	uint32_t			ncookies = 0;
25912011SSriharsha.Basavapatna@Sun.COM 	static char			*name = "vsw_setup_rx_dring";
26012011SSriharsha.Basavapatna@Sun.COM 	void				*data_addr = NULL;
26112011SSriharsha.Basavapatna@Sun.COM 
26212011SSriharsha.Basavapatna@Sun.COM 	/*
26312011SSriharsha.Basavapatna@Sun.COM 	 * Allocate a single large buffer that serves as the rx buffer area.
26412011SSriharsha.Basavapatna@Sun.COM 	 * We allocate a ldc memory handle and export the buffer area as shared
26512011SSriharsha.Basavapatna@Sun.COM 	 * memory. We send the ldc memcookie for this buffer space to the peer,
26612011SSriharsha.Basavapatna@Sun.COM 	 * as part of dring registration phase during handshake. We manage this
26712011SSriharsha.Basavapatna@Sun.COM 	 * buffer area as individual buffers of max_frame_size and provide
26812011SSriharsha.Basavapatna@Sun.COM 	 * specific buffer offsets in each descriptor to the peer. Note that
26912011SSriharsha.Basavapatna@Sun.COM 	 * the factor used to compute the # of buffers (above) must be > 1 to
27012011SSriharsha.Basavapatna@Sun.COM 	 * ensure that there are more buffers than the # of descriptors. This
27112011SSriharsha.Basavapatna@Sun.COM 	 * is needed because, while the shared memory buffers are sent up our
27212011SSriharsha.Basavapatna@Sun.COM 	 * stack during receive, the sender needs additional buffers that can
27312011SSriharsha.Basavapatna@Sun.COM 	 * be used for further transmits. This also means there is no one to
27412011SSriharsha.Basavapatna@Sun.COM 	 * one correspondence between the descriptor index and buffer offset.
27512011SSriharsha.Basavapatna@Sun.COM 	 * The sender has to read the buffer offset in the descriptor and use
27612011SSriharsha.Basavapatna@Sun.COM 	 * the specified offset to copy the tx data into the shared buffer. We
27712011SSriharsha.Basavapatna@Sun.COM 	 * (receiver) manage the individual buffers and their state (see
27812011SSriharsha.Basavapatna@Sun.COM 	 * VIO_MBLK_STATEs in vio_util.h).
27912011SSriharsha.Basavapatna@Sun.COM 	 */
280*13098SWentao.Yang@Sun.COM 	data_sz = RXDRING_DBLK_SZ(vswp->max_frame_size);
28112011SSriharsha.Basavapatna@Sun.COM 
28212011SSriharsha.Basavapatna@Sun.COM 	dp->desc_data_sz = data_sz;
28312011SSriharsha.Basavapatna@Sun.COM 	dp->data_sz = (dp->num_bufs * data_sz);
28412011SSriharsha.Basavapatna@Sun.COM 	data_addr = kmem_zalloc(dp->data_sz, KM_SLEEP);
28512011SSriharsha.Basavapatna@Sun.COM 	dp->data_addr = data_addr;
28612011SSriharsha.Basavapatna@Sun.COM 
28712011SSriharsha.Basavapatna@Sun.COM 	D2(vswp, "%s: allocated %lld bytes at 0x%llx\n", name,
28812011SSriharsha.Basavapatna@Sun.COM 	    dp->data_sz, dp->data_addr);
28912011SSriharsha.Basavapatna@Sun.COM 
29012011SSriharsha.Basavapatna@Sun.COM 	/* Allocate a ldc memhandle for the entire rx data area */
29112011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &dp->data_handle);
29212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
29312011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s: alloc mem handle failed", name);
29412011SSriharsha.Basavapatna@Sun.COM 		goto fail;
29512011SSriharsha.Basavapatna@Sun.COM 	}
29612011SSriharsha.Basavapatna@Sun.COM 
29712011SSriharsha.Basavapatna@Sun.COM 	/* Allocate memory for the data cookies */
29812011SSriharsha.Basavapatna@Sun.COM 	dp->data_cookie = kmem_zalloc(VNET_DATA_AREA_COOKIES *
29912011SSriharsha.Basavapatna@Sun.COM 	    sizeof (ldc_mem_cookie_t), KM_SLEEP);
30012011SSriharsha.Basavapatna@Sun.COM 
30112011SSriharsha.Basavapatna@Sun.COM 	/*
30212011SSriharsha.Basavapatna@Sun.COM 	 * Bind ldc memhandle to the corresponding rx data area.
30312011SSriharsha.Basavapatna@Sun.COM 	 */
30412011SSriharsha.Basavapatna@Sun.COM 	rv = ldc_mem_bind_handle(dp->data_handle, (caddr_t)data_addr,
30512011SSriharsha.Basavapatna@Sun.COM 	    dp->data_sz, LDC_DIRECT_MAP, LDC_MEM_W,
30612011SSriharsha.Basavapatna@Sun.COM 	    dp->data_cookie, &ncookies);
30712011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
30812011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s(%lld): ldc_mem_bind_handle failed "
30912011SSriharsha.Basavapatna@Sun.COM 		    "(rv %d)", name, ldcp->ldc_id, rv);
31012011SSriharsha.Basavapatna@Sun.COM 		goto fail;
31112011SSriharsha.Basavapatna@Sun.COM 	}
31212011SSriharsha.Basavapatna@Sun.COM 	if ((ncookies == 0) || (ncookies > VNET_DATA_AREA_COOKIES)) {
31312011SSriharsha.Basavapatna@Sun.COM 		goto fail;
31412011SSriharsha.Basavapatna@Sun.COM 	}
31512011SSriharsha.Basavapatna@Sun.COM 	dp->data_ncookies = ncookies;
31612011SSriharsha.Basavapatna@Sun.COM 
31712642SWentao.Yang@Sun.COM 	for (j = 1; j < ncookies; j++) {
31812642SWentao.Yang@Sun.COM 		rv = ldc_mem_nextcookie(dp->data_handle,
31912642SWentao.Yang@Sun.COM 		    &(dp->data_cookie[j]));
32012642SWentao.Yang@Sun.COM 		if (rv != 0) {
32112642SWentao.Yang@Sun.COM 			DERR(vswp, "%s: ldc_mem_nextcookie "
32212642SWentao.Yang@Sun.COM 			    "failed rv (%d)", name, rv);
32312642SWentao.Yang@Sun.COM 			goto fail;
32412642SWentao.Yang@Sun.COM 		}
32512642SWentao.Yang@Sun.COM 	}
32612642SWentao.Yang@Sun.COM 
32712011SSriharsha.Basavapatna@Sun.COM 	/*
32812011SSriharsha.Basavapatna@Sun.COM 	 * Successful in binding the handle to rx data area. Now setup mblks
32912011SSriharsha.Basavapatna@Sun.COM 	 * around each data buffer and setup the descriptors to point to these
33012011SSriharsha.Basavapatna@Sun.COM 	 * rx data buffers. We associate each descriptor with a buffer
33112011SSriharsha.Basavapatna@Sun.COM 	 * by specifying the buffer offset in the descriptor. When the peer
33212011SSriharsha.Basavapatna@Sun.COM 	 * needs to transmit data, this offset is read by the peer to determine
33312011SSriharsha.Basavapatna@Sun.COM 	 * the buffer in the mapped buffer area where the data to be
33412011SSriharsha.Basavapatna@Sun.COM 	 * transmitted should be copied, for a specific descriptor.
33512011SSriharsha.Basavapatna@Sun.COM 	 */
33612011SSriharsha.Basavapatna@Sun.COM 	rv = vio_create_mblks(dp->num_bufs, data_sz, (uint8_t *)data_addr,
33712011SSriharsha.Basavapatna@Sun.COM 	    &dp->rx_vmp);
33812011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
33912011SSriharsha.Basavapatna@Sun.COM 		goto fail;
34012011SSriharsha.Basavapatna@Sun.COM 	}
34112011SSriharsha.Basavapatna@Sun.COM 
34212011SSriharsha.Basavapatna@Sun.COM 	pub_addr = dp->pub_addr;
34312011SSriharsha.Basavapatna@Sun.COM 	rxdp_to_vmp = dp->rxdp_to_vmp;
34412011SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < dp->num_descriptors; i++) {
34512011SSriharsha.Basavapatna@Sun.COM 		rxdp = &pub_addr[i];
34612011SSriharsha.Basavapatna@Sun.COM 		/* allocate an mblk around this data buffer */
34712011SSriharsha.Basavapatna@Sun.COM 		vmp = vio_allocb(dp->rx_vmp);
34812011SSriharsha.Basavapatna@Sun.COM 		ASSERT(vmp != NULL);
34912011SSriharsha.Basavapatna@Sun.COM 		rxdp->data_buf_offset = VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN;
35012011SSriharsha.Basavapatna@Sun.COM 		rxdp->dstate = VIO_DESC_FREE;
35112011SSriharsha.Basavapatna@Sun.COM 		rxdp_to_vmp[i] = vmp;
35212011SSriharsha.Basavapatna@Sun.COM 	}
35312011SSriharsha.Basavapatna@Sun.COM 
35412011SSriharsha.Basavapatna@Sun.COM 	return (0);
35512011SSriharsha.Basavapatna@Sun.COM 
35612011SSriharsha.Basavapatna@Sun.COM fail:
35712011SSriharsha.Basavapatna@Sun.COM 	/* return failure; caller will cleanup */
35812011SSriharsha.Basavapatna@Sun.COM 	return (1);
35912011SSriharsha.Basavapatna@Sun.COM }
36012011SSriharsha.Basavapatna@Sun.COM 
36112011SSriharsha.Basavapatna@Sun.COM /*
36212011SSriharsha.Basavapatna@Sun.COM  * Free receive resources for the channel.
36312011SSriharsha.Basavapatna@Sun.COM  */
36412011SSriharsha.Basavapatna@Sun.COM void
vsw_destroy_rx_dring(vsw_ldc_t * ldcp)36512011SSriharsha.Basavapatna@Sun.COM vsw_destroy_rx_dring(vsw_ldc_t *ldcp)
36612011SSriharsha.Basavapatna@Sun.COM {
36712011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
36812011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
36912011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp;
37012011SSriharsha.Basavapatna@Sun.COM 
37112011SSriharsha.Basavapatna@Sun.COM 	dp = lp->dringp;
37212011SSriharsha.Basavapatna@Sun.COM 	if (dp == NULL) {
37312011SSriharsha.Basavapatna@Sun.COM 		return;
37412011SSriharsha.Basavapatna@Sun.COM 	}
37512011SSriharsha.Basavapatna@Sun.COM 
37612011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&dp->dlock);
37712011SSriharsha.Basavapatna@Sun.COM 
37812011SSriharsha.Basavapatna@Sun.COM 	if (dp->rx_vmp != NULL) {
37912011SSriharsha.Basavapatna@Sun.COM 		vio_clobber_pool(dp->rx_vmp);
38012011SSriharsha.Basavapatna@Sun.COM 		/*
38112011SSriharsha.Basavapatna@Sun.COM 		 * If we can't destroy the rx pool for this channel, dispatch a
38212011SSriharsha.Basavapatna@Sun.COM 		 * task to retry and clean up those rx pools. Note that we
38312011SSriharsha.Basavapatna@Sun.COM 		 * don't need to wait for the task to complete. If the vsw
38412011SSriharsha.Basavapatna@Sun.COM 		 * device itself gets detached (vsw_detach()), it will wait for
38512011SSriharsha.Basavapatna@Sun.COM 		 * the task to complete implicitly in ddi_taskq_destroy().
38612011SSriharsha.Basavapatna@Sun.COM 		 */
38712011SSriharsha.Basavapatna@Sun.COM 		if (vio_destroy_mblks(dp->rx_vmp) != 0)  {
38812011SSriharsha.Basavapatna@Sun.COM 			(void) ddi_taskq_dispatch(vswp->rxp_taskq,
38912011SSriharsha.Basavapatna@Sun.COM 			    vsw_destroy_rxpools, dp->rx_vmp, DDI_SLEEP);
39012011SSriharsha.Basavapatna@Sun.COM 		}
39112011SSriharsha.Basavapatna@Sun.COM 	}
39212011SSriharsha.Basavapatna@Sun.COM 
39312011SSriharsha.Basavapatna@Sun.COM 	/* Free rx data area cookies */
39412011SSriharsha.Basavapatna@Sun.COM 	if (dp->data_cookie != NULL) {
39512011SSriharsha.Basavapatna@Sun.COM 		kmem_free(dp->data_cookie, VNET_DATA_AREA_COOKIES *
39612011SSriharsha.Basavapatna@Sun.COM 		    sizeof (ldc_mem_cookie_t));
39712011SSriharsha.Basavapatna@Sun.COM 		dp->data_cookie = NULL;
39812011SSriharsha.Basavapatna@Sun.COM 	}
39912011SSriharsha.Basavapatna@Sun.COM 
40012011SSriharsha.Basavapatna@Sun.COM 	/* Unbind rx data area memhandle */
40112011SSriharsha.Basavapatna@Sun.COM 	if (dp->data_ncookies != 0) {
40212011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_unbind_handle(dp->data_handle);
40312011SSriharsha.Basavapatna@Sun.COM 		dp->data_ncookies = 0;
40412011SSriharsha.Basavapatna@Sun.COM 	}
40512011SSriharsha.Basavapatna@Sun.COM 
40612011SSriharsha.Basavapatna@Sun.COM 	/* Free rx data area memhandle */
40712011SSriharsha.Basavapatna@Sun.COM 	if (dp->data_handle) {
40812011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_free_handle(dp->data_handle);
40912011SSriharsha.Basavapatna@Sun.COM 		dp->data_handle = 0;
41012011SSriharsha.Basavapatna@Sun.COM 	}
41112011SSriharsha.Basavapatna@Sun.COM 
41212011SSriharsha.Basavapatna@Sun.COM 	/* Now free the rx data area itself */
41312011SSriharsha.Basavapatna@Sun.COM 	if (dp->data_addr != NULL) {
41412011SSriharsha.Basavapatna@Sun.COM 		kmem_free(dp->data_addr, dp->data_sz);
41512011SSriharsha.Basavapatna@Sun.COM 	}
41612011SSriharsha.Basavapatna@Sun.COM 
41712011SSriharsha.Basavapatna@Sun.COM 	/* Finally, free the receive descriptor ring */
41812011SSriharsha.Basavapatna@Sun.COM 	if (dp->dring_handle != NULL) {
41912011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unbind(dp->dring_handle);
42012011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_destroy(dp->dring_handle);
42112011SSriharsha.Basavapatna@Sun.COM 	}
42212011SSriharsha.Basavapatna@Sun.COM 
42312011SSriharsha.Basavapatna@Sun.COM 	if (dp->rxdp_to_vmp != NULL) {
42412011SSriharsha.Basavapatna@Sun.COM 		kmem_free(dp->rxdp_to_vmp,
42512011SSriharsha.Basavapatna@Sun.COM 		    dp->num_descriptors * sizeof (uintptr_t));
42612011SSriharsha.Basavapatna@Sun.COM 		dp->rxdp_to_vmp = NULL;
42712011SSriharsha.Basavapatna@Sun.COM 	}
42812011SSriharsha.Basavapatna@Sun.COM 
42912011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&dp->dlock);
43012011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&dp->dlock);
43112011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&dp->restart_lock);
43212011SSriharsha.Basavapatna@Sun.COM 	kmem_free(dp, sizeof (dring_info_t));
43312011SSriharsha.Basavapatna@Sun.COM 	lp->dringp = NULL;
43412011SSriharsha.Basavapatna@Sun.COM }
43512011SSriharsha.Basavapatna@Sun.COM 
43612011SSriharsha.Basavapatna@Sun.COM /*
43712011SSriharsha.Basavapatna@Sun.COM  * Map the receive descriptor ring exported by the peer, as our transmit
43812011SSriharsha.Basavapatna@Sun.COM  * descriptor ring.
43912011SSriharsha.Basavapatna@Sun.COM  */
44012011SSriharsha.Basavapatna@Sun.COM dring_info_t *
vsw_map_tx_dring(vsw_ldc_t * ldcp,void * pkt)44112011SSriharsha.Basavapatna@Sun.COM vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt)
44212011SSriharsha.Basavapatna@Sun.COM {
44312011SSriharsha.Basavapatna@Sun.COM 	int				i;
44412011SSriharsha.Basavapatna@Sun.COM 	int				rv;
44512011SSriharsha.Basavapatna@Sun.COM 	dring_info_t			*dp;
44612011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
44712011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
44812011SSriharsha.Basavapatna@Sun.COM 	vio_dring_reg_msg_t		*dring_pkt = pkt;
44912011SSriharsha.Basavapatna@Sun.COM 
45012011SSriharsha.Basavapatna@Sun.COM 	dp = vsw_map_dring_cmn(ldcp, dring_pkt);
45112011SSriharsha.Basavapatna@Sun.COM 	if (dp == NULL) {
45212011SSriharsha.Basavapatna@Sun.COM 		return (NULL);
45312011SSriharsha.Basavapatna@Sun.COM 	}
45412011SSriharsha.Basavapatna@Sun.COM 
45512011SSriharsha.Basavapatna@Sun.COM 	/* RxDringData mode specific initializations */
45612011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&dp->txlock, NULL, MUTEX_DRIVER, NULL);
45712011SSriharsha.Basavapatna@Sun.COM 	mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL);
45812950SWentao.Yang@Sun.COM 	dp->next_txi = dp->restart_peer_txi = 0;
45912011SSriharsha.Basavapatna@Sun.COM 	dp->restart_reqd = B_TRUE;
46012011SSriharsha.Basavapatna@Sun.COM 	ldcp->dringdata_msgid = 0;
46112011SSriharsha.Basavapatna@Sun.COM 	ldcp->lane_in.dringp = dp;
46212011SSriharsha.Basavapatna@Sun.COM 
46312011SSriharsha.Basavapatna@Sun.COM 	/*
46412011SSriharsha.Basavapatna@Sun.COM 	 * Mark the descriptor state as 'done'. This is implementation specific
46512011SSriharsha.Basavapatna@Sun.COM 	 * and not required by the protocol. In our implementation, we only
46612011SSriharsha.Basavapatna@Sun.COM 	 * need the descripor to be in 'done' state to be used by the transmit
46712011SSriharsha.Basavapatna@Sun.COM 	 * function and the peer is not aware of it. As the protocol requires
46812011SSriharsha.Basavapatna@Sun.COM 	 * that during initial registration the exporting end point mark the
46912011SSriharsha.Basavapatna@Sun.COM 	 * dstate as 'free', we change it 'done' here. After this, the dstate
47012011SSriharsha.Basavapatna@Sun.COM 	 * in our implementation will keep moving between 'ready', set by our
47112011SSriharsha.Basavapatna@Sun.COM 	 * transmit function; and and 'done', set by the peer (per protocol)
47212011SSriharsha.Basavapatna@Sun.COM 	 * after receiving data.
47312011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing dring shared memory area.
47412011SSriharsha.Basavapatna@Sun.COM 	 */
47512011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
47612011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
47712011SSriharsha.Basavapatna@Sun.COM 		/*
47812011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
47912011SSriharsha.Basavapatna@Sun.COM 		 * accessing the descriptors. Return failure.
48012011SSriharsha.Basavapatna@Sun.COM 		 */
48112011SSriharsha.Basavapatna@Sun.COM 		goto fail;
48212011SSriharsha.Basavapatna@Sun.COM 	}
48312011SSriharsha.Basavapatna@Sun.COM 
48412011SSriharsha.Basavapatna@Sun.COM 	txdp = (vnet_rx_dringdata_desc_t *)dp->pub_addr;
48512011SSriharsha.Basavapatna@Sun.COM 	for (i = 0; i < dp->num_descriptors; i++) {
48612011SSriharsha.Basavapatna@Sun.COM 		txdp[i].dstate = VIO_DESC_DONE;
48712011SSriharsha.Basavapatna@Sun.COM 	}
48812011SSriharsha.Basavapatna@Sun.COM 
48912011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
49012011SSriharsha.Basavapatna@Sun.COM 
49112011SSriharsha.Basavapatna@Sun.COM 	return (dp);
49212011SSriharsha.Basavapatna@Sun.COM 
49312011SSriharsha.Basavapatna@Sun.COM fail:
49412011SSriharsha.Basavapatna@Sun.COM 	if (dp->dring_handle != NULL) {
49512011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unmap(dp->dring_handle);
49612011SSriharsha.Basavapatna@Sun.COM 	}
49712011SSriharsha.Basavapatna@Sun.COM 	kmem_free(dp, sizeof (*dp));
49812011SSriharsha.Basavapatna@Sun.COM 	return (NULL);
49912011SSriharsha.Basavapatna@Sun.COM }
50012011SSriharsha.Basavapatna@Sun.COM 
50112011SSriharsha.Basavapatna@Sun.COM /*
50212011SSriharsha.Basavapatna@Sun.COM  * Unmap the transmit descriptor ring.
50312011SSriharsha.Basavapatna@Sun.COM  */
50412011SSriharsha.Basavapatna@Sun.COM void
vsw_unmap_tx_dring(vsw_ldc_t * ldcp)50512011SSriharsha.Basavapatna@Sun.COM vsw_unmap_tx_dring(vsw_ldc_t *ldcp)
50612011SSriharsha.Basavapatna@Sun.COM {
50712011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_in;
50812011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp;
50912011SSriharsha.Basavapatna@Sun.COM 
51012011SSriharsha.Basavapatna@Sun.COM 	if ((dp = lp->dringp) == NULL) {
51112011SSriharsha.Basavapatna@Sun.COM 		return;
51212011SSriharsha.Basavapatna@Sun.COM 	}
51312011SSriharsha.Basavapatna@Sun.COM 
51412011SSriharsha.Basavapatna@Sun.COM 	/* Unmap tx data area and free data handle */
51512011SSriharsha.Basavapatna@Sun.COM 	if (dp->data_handle != NULL) {
51612011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_unmap(dp->data_handle);
51712011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_free_handle(dp->data_handle);
51812011SSriharsha.Basavapatna@Sun.COM 		dp->data_handle = NULL;
51912011SSriharsha.Basavapatna@Sun.COM 	}
52012011SSriharsha.Basavapatna@Sun.COM 
52112011SSriharsha.Basavapatna@Sun.COM 	/* Free tx data area cookies */
52212011SSriharsha.Basavapatna@Sun.COM 	if (dp->data_cookie != NULL) {
52312011SSriharsha.Basavapatna@Sun.COM 		kmem_free(dp->data_cookie, dp->data_ncookies *
52412011SSriharsha.Basavapatna@Sun.COM 		    sizeof (ldc_mem_cookie_t));
52512011SSriharsha.Basavapatna@Sun.COM 		dp->data_cookie = NULL;
52612011SSriharsha.Basavapatna@Sun.COM 		dp->data_ncookies = 0;
52712011SSriharsha.Basavapatna@Sun.COM 	}
52812011SSriharsha.Basavapatna@Sun.COM 
52912011SSriharsha.Basavapatna@Sun.COM 	/* Unmap peer's dring */
53012011SSriharsha.Basavapatna@Sun.COM 	if (dp->dring_handle != NULL) {
53112011SSriharsha.Basavapatna@Sun.COM 		(void) ldc_mem_dring_unmap(dp->dring_handle);
53212011SSriharsha.Basavapatna@Sun.COM 		dp->dring_handle = NULL;
53312011SSriharsha.Basavapatna@Sun.COM 	}
53412011SSriharsha.Basavapatna@Sun.COM 
53512011SSriharsha.Basavapatna@Sun.COM 	mutex_destroy(&dp->txlock);
53612011SSriharsha.Basavapatna@Sun.COM 	kmem_free(dp, sizeof (dring_info_t));
53712011SSriharsha.Basavapatna@Sun.COM 	lp->dringp = NULL;
53812011SSriharsha.Basavapatna@Sun.COM }
53912011SSriharsha.Basavapatna@Sun.COM 
54012011SSriharsha.Basavapatna@Sun.COM /*
54112011SSriharsha.Basavapatna@Sun.COM  * A per LDC worker thread to process the rx dring and receive packets. This
54212011SSriharsha.Basavapatna@Sun.COM  * thread is woken up by the LDC interrupt handler when a dring data info
54312011SSriharsha.Basavapatna@Sun.COM  * message is received.
54412011SSriharsha.Basavapatna@Sun.COM  */
54512011SSriharsha.Basavapatna@Sun.COM void
vsw_ldc_rcv_worker(void * arg)54612011SSriharsha.Basavapatna@Sun.COM vsw_ldc_rcv_worker(void *arg)
54712011SSriharsha.Basavapatna@Sun.COM {
54812011SSriharsha.Basavapatna@Sun.COM 	callb_cpr_t	cprinfo;
54912011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t	*ldcp = (vsw_ldc_t *)arg;
55012011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
55112011SSriharsha.Basavapatna@Sun.COM 
55212011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
55312011SSriharsha.Basavapatna@Sun.COM 	CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr,
55412011SSriharsha.Basavapatna@Sun.COM 	    "vsw_rcv_thread");
55512011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->rcv_thr_lock);
55612011SSriharsha.Basavapatna@Sun.COM 	while (!(ldcp->rcv_thr_flags & VSW_WTHR_STOP)) {
55712011SSriharsha.Basavapatna@Sun.COM 
55812011SSriharsha.Basavapatna@Sun.COM 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
55912011SSriharsha.Basavapatna@Sun.COM 		/*
56012011SSriharsha.Basavapatna@Sun.COM 		 * Wait until the data is received or a stop
56112011SSriharsha.Basavapatna@Sun.COM 		 * request is received.
56212011SSriharsha.Basavapatna@Sun.COM 		 */
56312011SSriharsha.Basavapatna@Sun.COM 		while (!(ldcp->rcv_thr_flags &
56412011SSriharsha.Basavapatna@Sun.COM 		    (VSW_WTHR_DATARCVD | VSW_WTHR_STOP))) {
56512011SSriharsha.Basavapatna@Sun.COM 			cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock);
56612011SSriharsha.Basavapatna@Sun.COM 		}
56712011SSriharsha.Basavapatna@Sun.COM 		CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock)
56812011SSriharsha.Basavapatna@Sun.COM 
56912011SSriharsha.Basavapatna@Sun.COM 		/*
57012011SSriharsha.Basavapatna@Sun.COM 		 * First process the stop request.
57112011SSriharsha.Basavapatna@Sun.COM 		 */
57212011SSriharsha.Basavapatna@Sun.COM 		if (ldcp->rcv_thr_flags & VSW_WTHR_STOP) {
57312011SSriharsha.Basavapatna@Sun.COM 			D2(vswp, "%s(%lld):Rx thread stopped\n",
57412011SSriharsha.Basavapatna@Sun.COM 			    __func__, ldcp->ldc_id);
57512011SSriharsha.Basavapatna@Sun.COM 			break;
57612011SSriharsha.Basavapatna@Sun.COM 		}
57712011SSriharsha.Basavapatna@Sun.COM 		ldcp->rcv_thr_flags &= ~VSW_WTHR_DATARCVD;
57812011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&ldcp->rcv_thr_lock);
57912011SSriharsha.Basavapatna@Sun.COM 		D1(vswp, "%s(%lld):calling vsw_process_pkt\n",
58012011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id);
58112011SSriharsha.Basavapatna@Sun.COM 		vsw_ldc_rcv_shm(ldcp);
58212011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&ldcp->rcv_thr_lock);
58312011SSriharsha.Basavapatna@Sun.COM 	}
58412011SSriharsha.Basavapatna@Sun.COM 
58512011SSriharsha.Basavapatna@Sun.COM 	/*
58612011SSriharsha.Basavapatna@Sun.COM 	 * Update the run status and wakeup the thread that
58712011SSriharsha.Basavapatna@Sun.COM 	 * has sent the stop request.
58812011SSriharsha.Basavapatna@Sun.COM 	 */
58912011SSriharsha.Basavapatna@Sun.COM 	ldcp->rcv_thr_flags &= ~VSW_WTHR_STOP;
59012011SSriharsha.Basavapatna@Sun.COM 	ldcp->rcv_thread = NULL;
59112011SSriharsha.Basavapatna@Sun.COM 	CALLB_CPR_EXIT(&cprinfo);
59212011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
59312011SSriharsha.Basavapatna@Sun.COM 	thread_exit();
59412011SSriharsha.Basavapatna@Sun.COM }
59512011SSriharsha.Basavapatna@Sun.COM 
59612011SSriharsha.Basavapatna@Sun.COM /*
59712011SSriharsha.Basavapatna@Sun.COM  * Process the rx descriptor ring in the context of receive worker
59812011SSriharsha.Basavapatna@Sun.COM  * thread and switch the received packets to their destinations.
59912011SSriharsha.Basavapatna@Sun.COM  */
60012011SSriharsha.Basavapatna@Sun.COM static void
vsw_ldc_rcv_shm(vsw_ldc_t * ldcp)60112011SSriharsha.Basavapatna@Sun.COM vsw_ldc_rcv_shm(vsw_ldc_t *ldcp)
60212011SSriharsha.Basavapatna@Sun.COM {
60312011SSriharsha.Basavapatna@Sun.COM 	int		rv;
60412011SSriharsha.Basavapatna@Sun.COM 	uint32_t	end_ix;
60512011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t msg;
60612011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t	*msgp = &msg;
60712011SSriharsha.Basavapatna@Sun.COM 	int		count = 0;
60812011SSriharsha.Basavapatna@Sun.COM 	int		total_count = 0;
60912011SSriharsha.Basavapatna@Sun.COM 	uint32_t	retries = 0;
61012011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*bp = NULL;
61112011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*bpt = NULL;
61212011SSriharsha.Basavapatna@Sun.COM 	mblk_t		*mp = NULL;
61312011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
61412011SSriharsha.Basavapatna@Sun.COM 	lane_t		*lp = &ldcp->lane_out;
61512011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp = lp->dringp;
61612011SSriharsha.Basavapatna@Sun.COM 
61712011SSriharsha.Basavapatna@Sun.COM 	do {
61812011SSriharsha.Basavapatna@Sun.COM again:
61912011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_receive_packet(ldcp, &mp);
62012011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
62112011SSriharsha.Basavapatna@Sun.COM 			if (rv == EINVAL) {
62212011SSriharsha.Basavapatna@Sun.COM 				/* Invalid descriptor error; get next */
62312011SSriharsha.Basavapatna@Sun.COM 				continue;
62412011SSriharsha.Basavapatna@Sun.COM 			}
62512011SSriharsha.Basavapatna@Sun.COM 			if (rv != EAGAIN) {
62612011SSriharsha.Basavapatna@Sun.COM 				break;
62712011SSriharsha.Basavapatna@Sun.COM 			}
62812011SSriharsha.Basavapatna@Sun.COM 
62912011SSriharsha.Basavapatna@Sun.COM 			/* Descriptor not ready for processsing */
63012011SSriharsha.Basavapatna@Sun.COM 			if (retries == vsw_recv_retries) {
63112011SSriharsha.Basavapatna@Sun.COM 				DTRACE_PROBE1(vsw_noready_rxds,
63212011SSriharsha.Basavapatna@Sun.COM 				    vsw_ldc_t *, ldcp);
63312011SSriharsha.Basavapatna@Sun.COM 				break;
63412011SSriharsha.Basavapatna@Sun.COM 			}
63512011SSriharsha.Basavapatna@Sun.COM 
63612011SSriharsha.Basavapatna@Sun.COM 			/* Switch packets received so far before retrying */
63712011SSriharsha.Basavapatna@Sun.COM 			if (bp != NULL) {
63812011SSriharsha.Basavapatna@Sun.COM 				VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count,
63912011SSriharsha.Basavapatna@Sun.COM 				    total_count);
64012011SSriharsha.Basavapatna@Sun.COM 			}
64112011SSriharsha.Basavapatna@Sun.COM 			retries++;
64212011SSriharsha.Basavapatna@Sun.COM 			drv_usecwait(vsw_recv_delay);
64312011SSriharsha.Basavapatna@Sun.COM 			goto again;
64412011SSriharsha.Basavapatna@Sun.COM 		}
64512011SSriharsha.Basavapatna@Sun.COM 		retries = 0;
64612011SSriharsha.Basavapatna@Sun.COM 
64712011SSriharsha.Basavapatna@Sun.COM 		/* Build a chain of received packets */
64812011SSriharsha.Basavapatna@Sun.COM 		if (bp == NULL) {
64912011SSriharsha.Basavapatna@Sun.COM 			/* first pkt */
65012011SSriharsha.Basavapatna@Sun.COM 			bp = mp;
65112011SSriharsha.Basavapatna@Sun.COM 			bpt = bp;
65212011SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = NULL;
65312011SSriharsha.Basavapatna@Sun.COM 		} else {
65412011SSriharsha.Basavapatna@Sun.COM 			mp->b_next = NULL;
65512011SSriharsha.Basavapatna@Sun.COM 			bpt->b_next = mp;
65612011SSriharsha.Basavapatna@Sun.COM 			bpt = mp;
65712011SSriharsha.Basavapatna@Sun.COM 		}
65812011SSriharsha.Basavapatna@Sun.COM 
65912011SSriharsha.Basavapatna@Sun.COM 		total_count++;
66012011SSriharsha.Basavapatna@Sun.COM 		count++;
66112011SSriharsha.Basavapatna@Sun.COM 
66212011SSriharsha.Basavapatna@Sun.COM 		/*
66312011SSriharsha.Basavapatna@Sun.COM 		 * If we have gathered vsw_chain_len (tunable)
66412011SSriharsha.Basavapatna@Sun.COM 		 * # of packets in the chain, switch them.
66512011SSriharsha.Basavapatna@Sun.COM 		 */
66612011SSriharsha.Basavapatna@Sun.COM 		if (count == vsw_chain_len) {
66712011SSriharsha.Basavapatna@Sun.COM 			VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count,
66812011SSriharsha.Basavapatna@Sun.COM 			    total_count);
66912011SSriharsha.Basavapatna@Sun.COM 		}
67012011SSriharsha.Basavapatna@Sun.COM 
67112011SSriharsha.Basavapatna@Sun.COM 		/*
67212011SSriharsha.Basavapatna@Sun.COM 		 * Stop further processing if we processed the entire dring
67312011SSriharsha.Basavapatna@Sun.COM 		 * once; otherwise continue.
67412011SSriharsha.Basavapatna@Sun.COM 		 */
67512011SSriharsha.Basavapatna@Sun.COM 	} while (total_count < dp->num_bufs);
67612011SSriharsha.Basavapatna@Sun.COM 
67712011SSriharsha.Basavapatna@Sun.COM 	DTRACE_PROBE2(vsw_rx_total_count, vsw_ldc_t *, ldcp,
67812011SSriharsha.Basavapatna@Sun.COM 	    int, (total_count));
67912011SSriharsha.Basavapatna@Sun.COM 	if (bp != NULL) {
68012011SSriharsha.Basavapatna@Sun.COM 		VSW_SWITCH_FRAMES(vswp, ldcp, bp, bpt, count,
68112011SSriharsha.Basavapatna@Sun.COM 		    total_count);
68212011SSriharsha.Basavapatna@Sun.COM 	}
68312011SSriharsha.Basavapatna@Sun.COM 
68412011SSriharsha.Basavapatna@Sun.COM 	/* Send stopped signal to peer (sender) */
68512011SSriharsha.Basavapatna@Sun.COM 	end_ix = lp->dringp->next_rxi;
68612011SSriharsha.Basavapatna@Sun.COM 	DECR_RXI(dp, end_ix);
68712011SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_msgtype = VIO_TYPE_DATA;
68812011SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_subtype = VIO_SUBTYPE_ACK;
68912011SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_subtype_env = VIO_DRING_DATA;
69012011SSriharsha.Basavapatna@Sun.COM 	msgp->dring_ident = ldcp->lane_in.dringp->ident;
69112011SSriharsha.Basavapatna@Sun.COM 	msgp->tag.vio_sid = ldcp->local_session;
69212011SSriharsha.Basavapatna@Sun.COM 	msgp->dring_process_state = VIO_DP_STOPPED;
69312011SSriharsha.Basavapatna@Sun.COM 	msgp->start_idx = VNET_START_IDX_UNSPEC;
69412011SSriharsha.Basavapatna@Sun.COM 	msgp->end_idx = end_ix;
69512011SSriharsha.Basavapatna@Sun.COM 
69612011SSriharsha.Basavapatna@Sun.COM 	(void) vsw_send_msg_shm(ldcp, (void *)msgp,
69712011SSriharsha.Basavapatna@Sun.COM 	    sizeof (vio_dring_msg_t), B_TRUE);
69812011SSriharsha.Basavapatna@Sun.COM 
69912011SSriharsha.Basavapatna@Sun.COM 	ldcp->ldc_stats.dring_data_acks_sent++;
70012011SSriharsha.Basavapatna@Sun.COM 	ldcp->ldc_stats.dring_stopped_acks_sent++;
70112011SSriharsha.Basavapatna@Sun.COM }
70212011SSriharsha.Basavapatna@Sun.COM 
70312011SSriharsha.Basavapatna@Sun.COM /*
70412011SSriharsha.Basavapatna@Sun.COM  * Process the next index in the rx dring and receive the associated packet.
70512011SSriharsha.Basavapatna@Sun.COM  *
70612011SSriharsha.Basavapatna@Sun.COM  * Returns:
70712011SSriharsha.Basavapatna@Sun.COM  *	bp:	Success: The received packet.
70812011SSriharsha.Basavapatna@Sun.COM  *		Failure: NULL
70912011SSriharsha.Basavapatna@Sun.COM  *      retval:
71012011SSriharsha.Basavapatna@Sun.COM  *		Success: 0
71112011SSriharsha.Basavapatna@Sun.COM  *		Failure: EAGAIN: Descriptor not ready
71212011SSriharsha.Basavapatna@Sun.COM  *			 EIO:    Descriptor contents invalid.
71312011SSriharsha.Basavapatna@Sun.COM  */
71412011SSriharsha.Basavapatna@Sun.COM static int
vsw_receive_packet(vsw_ldc_t * ldcp,mblk_t ** bp)71512011SSriharsha.Basavapatna@Sun.COM vsw_receive_packet(vsw_ldc_t *ldcp, mblk_t **bp)
71612011SSriharsha.Basavapatna@Sun.COM {
71712011SSriharsha.Basavapatna@Sun.COM 	uint32_t			rxi;
71812011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			*vmp;
71912011SSriharsha.Basavapatna@Sun.COM 	vio_mblk_t			*new_vmp;
72012011SSriharsha.Basavapatna@Sun.COM 	struct ether_header		*ehp;
72112011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*rxdp;
72212011SSriharsha.Basavapatna@Sun.COM 	int				err = 0;
72312011SSriharsha.Basavapatna@Sun.COM 	uint_t				nbytes = 0;
72412011SSriharsha.Basavapatna@Sun.COM 	mblk_t				*mp = NULL;
72512011SSriharsha.Basavapatna@Sun.COM 	mblk_t				*dmp = NULL;
72612011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t			*statsp = &ldcp->ldc_stats;
72712011SSriharsha.Basavapatna@Sun.COM 	dring_info_t			*dp = ldcp->lane_out.dringp;
72812011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*pub_addr = dp->pub_addr;
72912011SSriharsha.Basavapatna@Sun.COM 
73012011SSriharsha.Basavapatna@Sun.COM 	rxi = dp->next_rxi;
73112011SSriharsha.Basavapatna@Sun.COM 	rxdp = &(pub_addr[rxi]);
73212011SSriharsha.Basavapatna@Sun.COM 	vmp = dp->rxdp_to_vmp[rxi];
73312011SSriharsha.Basavapatna@Sun.COM 
73412011SSriharsha.Basavapatna@Sun.COM 	if (rxdp->dstate != VIO_DESC_READY) {
73512011SSriharsha.Basavapatna@Sun.COM 		/*
73612011SSriharsha.Basavapatna@Sun.COM 		 * Descriptor is not ready.
73712011SSriharsha.Basavapatna@Sun.COM 		 */
73812011SSriharsha.Basavapatna@Sun.COM 		return (EAGAIN);
73912011SSriharsha.Basavapatna@Sun.COM 	}
74012011SSriharsha.Basavapatna@Sun.COM 
74112011SSriharsha.Basavapatna@Sun.COM 	/*
74212011SSriharsha.Basavapatna@Sun.COM 	 * Ensure load ordering of dstate and nbytes.
74312011SSriharsha.Basavapatna@Sun.COM 	 */
74412011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_CONSUMER();
74512011SSriharsha.Basavapatna@Sun.COM 
74612011SSriharsha.Basavapatna@Sun.COM 	if ((rxdp->nbytes < ETHERMIN) ||
74712011SSriharsha.Basavapatna@Sun.COM 	    (rxdp->nbytes > ldcp->lane_in.mtu) ||
74812011SSriharsha.Basavapatna@Sun.COM 	    (rxdp->data_buf_offset !=
74912011SSriharsha.Basavapatna@Sun.COM 	    (VIO_MBLK_DATA_OFF(vmp) + VNET_IPALIGN))) {
75012011SSriharsha.Basavapatna@Sun.COM 		/*
75112011SSriharsha.Basavapatna@Sun.COM 		 * Descriptor contents invalid.
75212011SSriharsha.Basavapatna@Sun.COM 		 */
75312011SSriharsha.Basavapatna@Sun.COM 		statsp->ierrors++;
75412011SSriharsha.Basavapatna@Sun.COM 		rxdp->dstate = VIO_DESC_DONE;
75512011SSriharsha.Basavapatna@Sun.COM 		err = EIO;
75612011SSriharsha.Basavapatna@Sun.COM 		goto done;
75712011SSriharsha.Basavapatna@Sun.COM 	}
75812011SSriharsha.Basavapatna@Sun.COM 
75912011SSriharsha.Basavapatna@Sun.COM 	/*
76012011SSriharsha.Basavapatna@Sun.COM 	 * Now allocate a new buffer for this descriptor before sending up the
76112011SSriharsha.Basavapatna@Sun.COM 	 * buffer being processed. If that fails, stop processing; as we are
76212011SSriharsha.Basavapatna@Sun.COM 	 * out of receive buffers.
76312011SSriharsha.Basavapatna@Sun.COM 	 */
76412011SSriharsha.Basavapatna@Sun.COM 	new_vmp = vio_allocb(dp->rx_vmp);
76512011SSriharsha.Basavapatna@Sun.COM 
76612011SSriharsha.Basavapatna@Sun.COM 	/*
76712011SSriharsha.Basavapatna@Sun.COM 	 * Process the current buffer being received.
76812011SSriharsha.Basavapatna@Sun.COM 	 */
76912011SSriharsha.Basavapatna@Sun.COM 	nbytes = rxdp->nbytes;
77012011SSriharsha.Basavapatna@Sun.COM 	mp = vmp->mp;
77112011SSriharsha.Basavapatna@Sun.COM 
77212011SSriharsha.Basavapatna@Sun.COM 	if (new_vmp == NULL) {
77312011SSriharsha.Basavapatna@Sun.COM 		/*
77412011SSriharsha.Basavapatna@Sun.COM 		 * We failed to get a new mapped buffer that is needed to
77512011SSriharsha.Basavapatna@Sun.COM 		 * refill the descriptor. In that case, leave the current
77612011SSriharsha.Basavapatna@Sun.COM 		 * buffer bound to the descriptor; allocate an mblk dynamically
77712011SSriharsha.Basavapatna@Sun.COM 		 * and copy the contents of the buffer to the mblk. Then send
77812011SSriharsha.Basavapatna@Sun.COM 		 * up this mblk. This way the sender has the same buffer as
77912011SSriharsha.Basavapatna@Sun.COM 		 * before that can be used to send new data.
78012011SSriharsha.Basavapatna@Sun.COM 		 */
78112011SSriharsha.Basavapatna@Sun.COM 		statsp->norcvbuf++;
78212011SSriharsha.Basavapatna@Sun.COM 		dmp = allocb(nbytes + VNET_IPALIGN, BPRI_MED);
78312011SSriharsha.Basavapatna@Sun.COM 		bcopy(mp->b_rptr + VNET_IPALIGN,
78412011SSriharsha.Basavapatna@Sun.COM 		    dmp->b_rptr + VNET_IPALIGN, nbytes);
78512011SSriharsha.Basavapatna@Sun.COM 		mp = dmp;
78612011SSriharsha.Basavapatna@Sun.COM 	} else {
78712011SSriharsha.Basavapatna@Sun.COM 		/* Mark the status of the current rbuf */
78812011SSriharsha.Basavapatna@Sun.COM 		vmp->state = VIO_MBLK_HAS_DATA;
78912011SSriharsha.Basavapatna@Sun.COM 
79012011SSriharsha.Basavapatna@Sun.COM 		/* Set the offset of the new buffer in the descriptor */
79112011SSriharsha.Basavapatna@Sun.COM 		rxdp->data_buf_offset =
79212011SSriharsha.Basavapatna@Sun.COM 		    VIO_MBLK_DATA_OFF(new_vmp) + VNET_IPALIGN;
79312011SSriharsha.Basavapatna@Sun.COM 		dp->rxdp_to_vmp[rxi] = new_vmp;
79412011SSriharsha.Basavapatna@Sun.COM 	}
79512011SSriharsha.Basavapatna@Sun.COM 	mp->b_rptr += VNET_IPALIGN;
79612011SSriharsha.Basavapatna@Sun.COM 	mp->b_wptr = mp->b_rptr + nbytes;
79712011SSriharsha.Basavapatna@Sun.COM 
79812011SSriharsha.Basavapatna@Sun.COM 	/*
79912011SSriharsha.Basavapatna@Sun.COM 	 * Ensure store ordering of data_buf_offset and dstate; so that the
80012011SSriharsha.Basavapatna@Sun.COM 	 * peer sees the right data_buf_offset after it checks that the dstate
80112011SSriharsha.Basavapatna@Sun.COM 	 * is DONE.
80212011SSriharsha.Basavapatna@Sun.COM 	 */
80312011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_PRODUCER();
80412011SSriharsha.Basavapatna@Sun.COM 
80512011SSriharsha.Basavapatna@Sun.COM 	/* Now mark the descriptor 'done' */
80612011SSriharsha.Basavapatna@Sun.COM 	rxdp->dstate = VIO_DESC_DONE;
80712011SSriharsha.Basavapatna@Sun.COM 
80812011SSriharsha.Basavapatna@Sun.COM 	/* Update stats */
80912011SSriharsha.Basavapatna@Sun.COM 	statsp->ipackets++;
81012011SSriharsha.Basavapatna@Sun.COM 	statsp->rbytes += rxdp->nbytes;
81112011SSriharsha.Basavapatna@Sun.COM 	ehp = (struct ether_header *)mp->b_rptr;
81212011SSriharsha.Basavapatna@Sun.COM 	if (IS_BROADCAST(ehp))
81312011SSriharsha.Basavapatna@Sun.COM 		statsp->brdcstrcv++;
81412011SSriharsha.Basavapatna@Sun.COM 	else if (IS_MULTICAST(ehp))
81512011SSriharsha.Basavapatna@Sun.COM 		statsp->multircv++;
81612011SSriharsha.Basavapatna@Sun.COM done:
81712011SSriharsha.Basavapatna@Sun.COM 	/* Update the next index to be processed */
81812011SSriharsha.Basavapatna@Sun.COM 	INCR_RXI(dp, rxi);
81912011SSriharsha.Basavapatna@Sun.COM 
82012011SSriharsha.Basavapatna@Sun.COM 	/* Save the new recv index */
82112011SSriharsha.Basavapatna@Sun.COM 	dp->next_rxi = rxi;
82212011SSriharsha.Basavapatna@Sun.COM 
82312011SSriharsha.Basavapatna@Sun.COM 	/* Return the packet received */
82412011SSriharsha.Basavapatna@Sun.COM 	*bp = mp;
82512011SSriharsha.Basavapatna@Sun.COM 	return (err);
82612011SSriharsha.Basavapatna@Sun.COM }
82712011SSriharsha.Basavapatna@Sun.COM 
82812011SSriharsha.Basavapatna@Sun.COM void
vsw_stop_rcv_thread(vsw_ldc_t * ldcp)82912011SSriharsha.Basavapatna@Sun.COM vsw_stop_rcv_thread(vsw_ldc_t *ldcp)
83012011SSriharsha.Basavapatna@Sun.COM {
83112011SSriharsha.Basavapatna@Sun.COM 	kt_did_t	tid = 0;
83212011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
83312011SSriharsha.Basavapatna@Sun.COM 
83412011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id);
83512011SSriharsha.Basavapatna@Sun.COM 	/*
83612011SSriharsha.Basavapatna@Sun.COM 	 * Send a stop request by setting the stop flag and
83712011SSriharsha.Basavapatna@Sun.COM 	 * wait until the rcv process thread stops.
83812011SSriharsha.Basavapatna@Sun.COM 	 */
83912011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->rcv_thr_lock);
84012011SSriharsha.Basavapatna@Sun.COM 	if (ldcp->rcv_thread != NULL) {
84112011SSriharsha.Basavapatna@Sun.COM 		tid = ldcp->rcv_thread->t_did;
84212011SSriharsha.Basavapatna@Sun.COM 		ldcp->rcv_thr_flags |= VSW_WTHR_STOP;
84312011SSriharsha.Basavapatna@Sun.COM 		cv_signal(&ldcp->rcv_thr_cv);
84412011SSriharsha.Basavapatna@Sun.COM 	}
84512011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->rcv_thr_lock);
84612011SSriharsha.Basavapatna@Sun.COM 
84712011SSriharsha.Basavapatna@Sun.COM 	if (tid != 0) {
84812011SSriharsha.Basavapatna@Sun.COM 		thread_join(tid);
84912011SSriharsha.Basavapatna@Sun.COM 	}
85012011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id);
85112011SSriharsha.Basavapatna@Sun.COM }
85212011SSriharsha.Basavapatna@Sun.COM 
85312011SSriharsha.Basavapatna@Sun.COM int
vsw_dringsend_shm(vsw_ldc_t * ldcp,mblk_t * mp)85412011SSriharsha.Basavapatna@Sun.COM vsw_dringsend_shm(vsw_ldc_t *ldcp, mblk_t *mp)
85512011SSriharsha.Basavapatna@Sun.COM {
85612011SSriharsha.Basavapatna@Sun.COM 	uint32_t			next_txi;
85712011SSriharsha.Basavapatna@Sun.COM 	uint32_t			txi;
85812011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
85912011SSriharsha.Basavapatna@Sun.COM 	struct ether_header		*ehp;
86012011SSriharsha.Basavapatna@Sun.COM 	size_t				mblksz;
86112011SSriharsha.Basavapatna@Sun.COM 	caddr_t				dst;
86212011SSriharsha.Basavapatna@Sun.COM 	mblk_t				*bp;
86312011SSriharsha.Basavapatna@Sun.COM 	size_t				size;
86412011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
86512011SSriharsha.Basavapatna@Sun.COM 	uint32_t			buf_offset;
86612011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*pub_addr;
86712011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t			msg;
86812011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t			*msgp = &msg;
86912011SSriharsha.Basavapatna@Sun.COM 	int				rv = 0;
87012011SSriharsha.Basavapatna@Sun.COM 	boolean_t			resched_peer = B_FALSE;
87112011SSriharsha.Basavapatna@Sun.COM 	boolean_t			is_bcast = B_FALSE;
87212011SSriharsha.Basavapatna@Sun.COM 	boolean_t			is_mcast = B_FALSE;
87312011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t			*statsp = &ldcp->ldc_stats;
87412011SSriharsha.Basavapatna@Sun.COM 	lane_t				*lane_in = &ldcp->lane_in;
87512011SSriharsha.Basavapatna@Sun.COM 	lane_t				*lane_out = &ldcp->lane_out;
87612011SSriharsha.Basavapatna@Sun.COM 	dring_info_t			*dp = lane_in->dringp;
87712011SSriharsha.Basavapatna@Sun.COM 	vsw_t				*vswp = ldcp->ldc_vswp;
87812011SSriharsha.Basavapatna@Sun.COM 
87912011SSriharsha.Basavapatna@Sun.COM 	if ((!(lane_in->lstate & VSW_LANE_ACTIVE)) ||
88012011SSriharsha.Basavapatna@Sun.COM 	    (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) {
88112011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
88212011SSriharsha.Basavapatna@Sun.COM 		    "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
88312011SSriharsha.Basavapatna@Sun.COM 		    lane_in->lstate);
88412011SSriharsha.Basavapatna@Sun.COM 		statsp->oerrors++;
88512011SSriharsha.Basavapatna@Sun.COM 		return (LDC_TX_FAILURE);
88612011SSriharsha.Basavapatna@Sun.COM 	}
88712011SSriharsha.Basavapatna@Sun.COM 
88812011SSriharsha.Basavapatna@Sun.COM 	if (dp == NULL) {
88912011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s(%lld): no dring for outbound lane on"
89012011SSriharsha.Basavapatna@Sun.COM 		    " channel %d", __func__, ldcp->ldc_id, ldcp->ldc_id);
89112011SSriharsha.Basavapatna@Sun.COM 		statsp->oerrors++;
89212011SSriharsha.Basavapatna@Sun.COM 		return (LDC_TX_FAILURE);
89312011SSriharsha.Basavapatna@Sun.COM 	}
89412011SSriharsha.Basavapatna@Sun.COM 	pub_addr = dp->pub_addr;
89512011SSriharsha.Basavapatna@Sun.COM 
89612011SSriharsha.Basavapatna@Sun.COM 	size = msgsize(mp);
89712011SSriharsha.Basavapatna@Sun.COM 
89812011SSriharsha.Basavapatna@Sun.COM 	/*
89912011SSriharsha.Basavapatna@Sun.COM 	 * Note: In RxDringData mode, lane_in is associated with transmit and
90012011SSriharsha.Basavapatna@Sun.COM 	 * lane_out is associated with receive. However, we still keep the
90112011SSriharsha.Basavapatna@Sun.COM 	 * negotiated mtu in lane_out (our exported attributes).
90212011SSriharsha.Basavapatna@Sun.COM 	 */
90312011SSriharsha.Basavapatna@Sun.COM 	if (size > (size_t)lane_out->mtu) {
90412011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__,
90512011SSriharsha.Basavapatna@Sun.COM 		    ldcp->ldc_id, size);
90612011SSriharsha.Basavapatna@Sun.COM 		statsp->oerrors++;
90712011SSriharsha.Basavapatna@Sun.COM 		return (LDC_TX_FAILURE);
90812011SSriharsha.Basavapatna@Sun.COM 	}
90912011SSriharsha.Basavapatna@Sun.COM 
91012011SSriharsha.Basavapatna@Sun.COM 	if (size < ETHERMIN)
91112011SSriharsha.Basavapatna@Sun.COM 		size = ETHERMIN;
91212011SSriharsha.Basavapatna@Sun.COM 
91312011SSriharsha.Basavapatna@Sun.COM 	ehp = (struct ether_header *)mp->b_rptr;
91412011SSriharsha.Basavapatna@Sun.COM 	is_bcast = IS_BROADCAST(ehp);
91512011SSriharsha.Basavapatna@Sun.COM 	is_mcast = IS_MULTICAST(ehp);
91612011SSriharsha.Basavapatna@Sun.COM 
91712011SSriharsha.Basavapatna@Sun.COM 	/*
91812011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing shared memory areas
91912011SSriharsha.Basavapatna@Sun.COM 	 * (descriptor and data buffer). Note that we enable this protection a
92012011SSriharsha.Basavapatna@Sun.COM 	 * little early and turn it off slightly later, than keeping it enabled
92112011SSriharsha.Basavapatna@Sun.COM 	 * strictly at the points in code below where the descriptor and data
92212011SSriharsha.Basavapatna@Sun.COM 	 * buffer are accessed. This is done for performance reasons:
92312011SSriharsha.Basavapatna@Sun.COM 	 * (a) to avoid calling the trap protection code while holding mutex.
92412011SSriharsha.Basavapatna@Sun.COM 	 * (b) to avoid multiple on/off steps for descriptor and data accesses.
92512011SSriharsha.Basavapatna@Sun.COM 	 */
92612011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
92712011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
92812011SSriharsha.Basavapatna@Sun.COM 		/*
92912011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
93012011SSriharsha.Basavapatna@Sun.COM 		 * accessing either the descriptor or the data buffer. Release
93112011SSriharsha.Basavapatna@Sun.COM 		 * any locks that we might have acquired in the code below and
93212011SSriharsha.Basavapatna@Sun.COM 		 * return failure.
93312011SSriharsha.Basavapatna@Sun.COM 		 */
93412011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s(%lld) data access fault occured\n",
93512011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id);
93612011SSriharsha.Basavapatna@Sun.COM 		statsp->oerrors++;
93712011SSriharsha.Basavapatna@Sun.COM 		if (mutex_owned(&dp->txlock)) {
93812011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&dp->txlock);
93912011SSriharsha.Basavapatna@Sun.COM 		}
94012011SSriharsha.Basavapatna@Sun.COM 		if (mutex_owned(&dp->restart_lock)) {
94112011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&dp->restart_lock);
94212011SSriharsha.Basavapatna@Sun.COM 		}
94312011SSriharsha.Basavapatna@Sun.COM 		goto dringsend_shm_exit;
94412011SSriharsha.Basavapatna@Sun.COM 	}
94512011SSriharsha.Basavapatna@Sun.COM 
94612011SSriharsha.Basavapatna@Sun.COM 	/*
94712011SSriharsha.Basavapatna@Sun.COM 	 * Allocate a descriptor
94812011SSriharsha.Basavapatna@Sun.COM 	 */
94912011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&dp->txlock);
95012011SSriharsha.Basavapatna@Sun.COM 	txi = next_txi = dp->next_txi;
95112011SSriharsha.Basavapatna@Sun.COM 	INCR_TXI(dp, next_txi);
95212950SWentao.Yang@Sun.COM 	txdp = &(pub_addr[txi]);
95312950SWentao.Yang@Sun.COM 	if (txdp->dstate != VIO_DESC_DONE) { /* out of descriptors */
95412011SSriharsha.Basavapatna@Sun.COM 		statsp->tx_no_desc++;
95512011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&dp->txlock);
95612011SSriharsha.Basavapatna@Sun.COM 		(void) LDC_NO_TRAP();
95712011SSriharsha.Basavapatna@Sun.COM 		return (LDC_TX_NORESOURCES);
95812950SWentao.Yang@Sun.COM 	} else {
95912950SWentao.Yang@Sun.COM 		txdp->dstate = VIO_DESC_INITIALIZING;
96012011SSriharsha.Basavapatna@Sun.COM 	}
96112011SSriharsha.Basavapatna@Sun.COM 
96212011SSriharsha.Basavapatna@Sun.COM 	/* Update descriptor ring index */
96312011SSriharsha.Basavapatna@Sun.COM 	dp->next_txi = next_txi;
96412011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&dp->txlock);
96512011SSriharsha.Basavapatna@Sun.COM 
96612011SSriharsha.Basavapatna@Sun.COM 	/* Ensure load ordering of dstate (above) and data_buf_offset. */
96712011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_CONSUMER();
96812011SSriharsha.Basavapatna@Sun.COM 
96912011SSriharsha.Basavapatna@Sun.COM 	/* Get the offset of the buffer to be used */
97012011SSriharsha.Basavapatna@Sun.COM 	buf_offset = txdp->data_buf_offset;
97112011SSriharsha.Basavapatna@Sun.COM 
97212011SSriharsha.Basavapatna@Sun.COM 	/* Access the buffer using the offset */
97312011SSriharsha.Basavapatna@Sun.COM 	dst = (caddr_t)dp->data_addr + buf_offset;
97412011SSriharsha.Basavapatna@Sun.COM 
97512011SSriharsha.Basavapatna@Sun.COM 	/* Copy data into mapped transmit buffer */
97612011SSriharsha.Basavapatna@Sun.COM 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
97712011SSriharsha.Basavapatna@Sun.COM 		mblksz = MBLKL(bp);
97812011SSriharsha.Basavapatna@Sun.COM 		bcopy(bp->b_rptr, dst, mblksz);
97912011SSriharsha.Basavapatna@Sun.COM 		dst += mblksz;
98012011SSriharsha.Basavapatna@Sun.COM 	}
98112011SSriharsha.Basavapatna@Sun.COM 
98212011SSriharsha.Basavapatna@Sun.COM 	/* Set the size of data in the descriptor */
98312011SSriharsha.Basavapatna@Sun.COM 	txdp->nbytes = size;
98412011SSriharsha.Basavapatna@Sun.COM 
98512011SSriharsha.Basavapatna@Sun.COM 	/*
98612011SSriharsha.Basavapatna@Sun.COM 	 * Ensure store ordering of nbytes and dstate (below); so that the peer
98712011SSriharsha.Basavapatna@Sun.COM 	 * sees the right nbytes value after it checks that the dstate is READY.
98812011SSriharsha.Basavapatna@Sun.COM 	 */
98912011SSriharsha.Basavapatna@Sun.COM 	MEMBAR_PRODUCER();
99012011SSriharsha.Basavapatna@Sun.COM 
99112011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&dp->restart_lock);
99212011SSriharsha.Basavapatna@Sun.COM 
99312950SWentao.Yang@Sun.COM 	ASSERT(txdp->dstate == VIO_DESC_INITIALIZING);
99412950SWentao.Yang@Sun.COM 
99512011SSriharsha.Basavapatna@Sun.COM 	/* Mark the descriptor ready */
99612011SSriharsha.Basavapatna@Sun.COM 	txdp->dstate = VIO_DESC_READY;
99712011SSriharsha.Basavapatna@Sun.COM 
99812011SSriharsha.Basavapatna@Sun.COM 	/* Check if peer needs wake up (handled below) */
99912950SWentao.Yang@Sun.COM 	if (dp->restart_reqd == B_TRUE && dp->restart_peer_txi == txi) {
100012011SSriharsha.Basavapatna@Sun.COM 		dp->restart_reqd = B_FALSE;
100112011SSriharsha.Basavapatna@Sun.COM 		resched_peer = B_TRUE;
100212011SSriharsha.Basavapatna@Sun.COM 	}
100312011SSriharsha.Basavapatna@Sun.COM 
100412011SSriharsha.Basavapatna@Sun.COM 	/* Update tx stats */
100512011SSriharsha.Basavapatna@Sun.COM 	statsp->opackets++;
100612011SSriharsha.Basavapatna@Sun.COM 	statsp->obytes += size;
100712011SSriharsha.Basavapatna@Sun.COM 	if (is_bcast)
100812011SSriharsha.Basavapatna@Sun.COM 		statsp->brdcstxmt++;
100912011SSriharsha.Basavapatna@Sun.COM 	else if (is_mcast)
101012011SSriharsha.Basavapatna@Sun.COM 		statsp->multixmt++;
101112011SSriharsha.Basavapatna@Sun.COM 
101212011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&dp->restart_lock);
101312011SSriharsha.Basavapatna@Sun.COM 
101412011SSriharsha.Basavapatna@Sun.COM 	/*
101512011SSriharsha.Basavapatna@Sun.COM 	 * We are done accessing shared memory; clear trap protection.
101612011SSriharsha.Basavapatna@Sun.COM 	 */
101712011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
101812011SSriharsha.Basavapatna@Sun.COM 
101912011SSriharsha.Basavapatna@Sun.COM 	/*
102012011SSriharsha.Basavapatna@Sun.COM 	 * Need to wake up the peer ?
102112011SSriharsha.Basavapatna@Sun.COM 	 */
102212011SSriharsha.Basavapatna@Sun.COM 	if (resched_peer == B_TRUE) {
102312011SSriharsha.Basavapatna@Sun.COM 		msgp->tag.vio_msgtype = VIO_TYPE_DATA;
102412011SSriharsha.Basavapatna@Sun.COM 		msgp->tag.vio_subtype = VIO_SUBTYPE_INFO;
102512011SSriharsha.Basavapatna@Sun.COM 		msgp->tag.vio_subtype_env = VIO_DRING_DATA;
102612011SSriharsha.Basavapatna@Sun.COM 		msgp->tag.vio_sid = ldcp->local_session;
102712011SSriharsha.Basavapatna@Sun.COM 		msgp->dring_ident = lane_out->dringp->ident;
102812011SSriharsha.Basavapatna@Sun.COM 		msgp->start_idx = txi;
102912011SSriharsha.Basavapatna@Sun.COM 		msgp->end_idx = -1;
103012011SSriharsha.Basavapatna@Sun.COM 
103112011SSriharsha.Basavapatna@Sun.COM 		rv = vsw_send_msg_shm(ldcp, (void *)msgp, sizeof (*msgp),
103212011SSriharsha.Basavapatna@Sun.COM 		    B_FALSE);
103312011SSriharsha.Basavapatna@Sun.COM 		if (rv != 0) {
103412011SSriharsha.Basavapatna@Sun.COM 			/* error: drop the packet */
103512011SSriharsha.Basavapatna@Sun.COM 			DERR(vswp, "%s(%lld) failed sending dringdata msg\n",
103612011SSriharsha.Basavapatna@Sun.COM 			    __func__, ldcp->ldc_id);
103712011SSriharsha.Basavapatna@Sun.COM 			mutex_enter(&dp->restart_lock);
103812011SSriharsha.Basavapatna@Sun.COM 			statsp->oerrors++;
103912011SSriharsha.Basavapatna@Sun.COM 			dp->restart_reqd = B_TRUE;
104012011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&dp->restart_lock);
104112011SSriharsha.Basavapatna@Sun.COM 		}
104212011SSriharsha.Basavapatna@Sun.COM 		statsp->dring_data_msgs_sent++;
104312011SSriharsha.Basavapatna@Sun.COM 	}
104412011SSriharsha.Basavapatna@Sun.COM 
104512011SSriharsha.Basavapatna@Sun.COM dringsend_shm_exit:
104612011SSriharsha.Basavapatna@Sun.COM 	if (rv == ECONNRESET || rv == EACCES) {
104712011SSriharsha.Basavapatna@Sun.COM 		vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
104812011SSriharsha.Basavapatna@Sun.COM 	}
104912011SSriharsha.Basavapatna@Sun.COM 	return (LDC_TX_SUCCESS);
105012011SSriharsha.Basavapatna@Sun.COM }
105112011SSriharsha.Basavapatna@Sun.COM 
105212011SSriharsha.Basavapatna@Sun.COM void
vsw_process_dringdata_shm(void * arg,void * dpkt)105312011SSriharsha.Basavapatna@Sun.COM vsw_process_dringdata_shm(void *arg, void *dpkt)
105412011SSriharsha.Basavapatna@Sun.COM {
105512011SSriharsha.Basavapatna@Sun.COM 	vsw_ldc_t		*ldcp = arg;
105612011SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
105712011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t		*dring_pkt = dpkt;
105812011SSriharsha.Basavapatna@Sun.COM 
105912011SSriharsha.Basavapatna@Sun.COM 	switch (dring_pkt->tag.vio_subtype) {
106012011SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_INFO:
106112011SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s(%lld): VIO_SUBTYPE_INFO", __func__, ldcp->ldc_id);
106212011SSriharsha.Basavapatna@Sun.COM 		vsw_process_dringdata_info_shm(ldcp, dring_pkt);
106312011SSriharsha.Basavapatna@Sun.COM 		break;
106412011SSriharsha.Basavapatna@Sun.COM 
106512011SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_ACK:
106612011SSriharsha.Basavapatna@Sun.COM 		D2(vswp, "%s(%lld): VIO_SUBTYPE_ACK", __func__, ldcp->ldc_id);
106712011SSriharsha.Basavapatna@Sun.COM 		vsw_process_dringdata_ack_shm(ldcp, dring_pkt);
106812011SSriharsha.Basavapatna@Sun.COM 		break;
106912011SSriharsha.Basavapatna@Sun.COM 
107012011SSriharsha.Basavapatna@Sun.COM 	case VIO_SUBTYPE_NACK:
107112011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s(%lld): VIO_SUBTYPE_NACK",
107212011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id);
107312011SSriharsha.Basavapatna@Sun.COM 		/*
107412011SSriharsha.Basavapatna@Sun.COM 		 * Something is badly wrong if we are getting NACK's
107512011SSriharsha.Basavapatna@Sun.COM 		 * for our data pkts. So reset the channel.
107612011SSriharsha.Basavapatna@Sun.COM 		 */
107712011SSriharsha.Basavapatna@Sun.COM 		vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
107812011SSriharsha.Basavapatna@Sun.COM 		break;
107912011SSriharsha.Basavapatna@Sun.COM 
108012011SSriharsha.Basavapatna@Sun.COM 	default:
108112011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__,
108212011SSriharsha.Basavapatna@Sun.COM 		    ldcp->ldc_id, dring_pkt->tag.vio_subtype);
108312011SSriharsha.Basavapatna@Sun.COM 	}
108412011SSriharsha.Basavapatna@Sun.COM }
108512011SSriharsha.Basavapatna@Sun.COM 
108612011SSriharsha.Basavapatna@Sun.COM static void
vsw_process_dringdata_info_shm(vsw_ldc_t * ldcp,vio_dring_msg_t * msg)108712011SSriharsha.Basavapatna@Sun.COM vsw_process_dringdata_info_shm(vsw_ldc_t *ldcp, vio_dring_msg_t *msg)
108812011SSriharsha.Basavapatna@Sun.COM {
108912011SSriharsha.Basavapatna@Sun.COM 	dring_info_t	*dp = ldcp->lane_in.dringp;
109012011SSriharsha.Basavapatna@Sun.COM 	vsw_t		*vswp = ldcp->ldc_vswp;
109112011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t	*statsp = &ldcp->ldc_stats;
109212011SSriharsha.Basavapatna@Sun.COM 
109312011SSriharsha.Basavapatna@Sun.COM 	if (dp->ident != msg->dring_ident) {
109412011SSriharsha.Basavapatna@Sun.COM 		/* drop the message */
109512011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "%s(%lld): Invalid dring ident 0x%llx",
109612011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id, msg->dring_ident);
109712011SSriharsha.Basavapatna@Sun.COM 		return;
109812011SSriharsha.Basavapatna@Sun.COM 	}
109912011SSriharsha.Basavapatna@Sun.COM 
110012011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_msgs_rcvd++;
110112011SSriharsha.Basavapatna@Sun.COM 
110212011SSriharsha.Basavapatna@Sun.COM 	/*
110312011SSriharsha.Basavapatna@Sun.COM 	 * Wake up the rcv worker thread to process the rx dring.
110412011SSriharsha.Basavapatna@Sun.COM 	 */
110512011SSriharsha.Basavapatna@Sun.COM 	ASSERT(MUTEX_HELD(&ldcp->ldc_cblock));
110612011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->ldc_cblock);
110712011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->rcv_thr_lock);
110812011SSriharsha.Basavapatna@Sun.COM 	if (!(ldcp->rcv_thr_flags & VSW_WTHR_DATARCVD)) {
110912011SSriharsha.Basavapatna@Sun.COM 		ldcp->rcv_thr_flags |= VSW_WTHR_DATARCVD;
111012011SSriharsha.Basavapatna@Sun.COM 		cv_signal(&ldcp->rcv_thr_cv);
111112011SSriharsha.Basavapatna@Sun.COM 	}
111212011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&ldcp->rcv_thr_lock);
111312011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&ldcp->ldc_cblock);
111412011SSriharsha.Basavapatna@Sun.COM }
111512011SSriharsha.Basavapatna@Sun.COM 
111612011SSriharsha.Basavapatna@Sun.COM static void
vsw_process_dringdata_ack_shm(vsw_ldc_t * ldcp,vio_dring_msg_t * msg)111712011SSriharsha.Basavapatna@Sun.COM vsw_process_dringdata_ack_shm(vsw_ldc_t *ldcp, vio_dring_msg_t *msg)
111812011SSriharsha.Basavapatna@Sun.COM {
111912011SSriharsha.Basavapatna@Sun.COM 	dring_info_t			*dp;
112012011SSriharsha.Basavapatna@Sun.COM 	uint32_t			start;
112112011SSriharsha.Basavapatna@Sun.COM 	int32_t				end;
112212011SSriharsha.Basavapatna@Sun.COM 	int				rv;
112312011SSriharsha.Basavapatna@Sun.COM 	on_trap_data_t			otd;
112412011SSriharsha.Basavapatna@Sun.COM 	uint32_t			txi;
112512011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*txdp;
112612011SSriharsha.Basavapatna@Sun.COM 	vnet_rx_dringdata_desc_t	*pub_addr;
112712011SSriharsha.Basavapatna@Sun.COM 	boolean_t			ready_txd = B_FALSE;
112812011SSriharsha.Basavapatna@Sun.COM 	vsw_t				*vswp = ldcp->ldc_vswp;
112912011SSriharsha.Basavapatna@Sun.COM 	vgen_stats_t			*statsp = &ldcp->ldc_stats;
113012011SSriharsha.Basavapatna@Sun.COM 
113112011SSriharsha.Basavapatna@Sun.COM 	dp = ldcp->lane_in.dringp;
113212011SSriharsha.Basavapatna@Sun.COM 	start = msg->start_idx;
113312011SSriharsha.Basavapatna@Sun.COM 	end = msg->end_idx;
113412011SSriharsha.Basavapatna@Sun.COM 	pub_addr = dp->pub_addr;
113512011SSriharsha.Basavapatna@Sun.COM 
113612011SSriharsha.Basavapatna@Sun.COM 	/*
113712011SSriharsha.Basavapatna@Sun.COM 	 * In RxDringData mode (v1.6), start index of -1 can be used by the
113812011SSriharsha.Basavapatna@Sun.COM 	 * peer to indicate that it is unspecified. However, the end index
113912011SSriharsha.Basavapatna@Sun.COM 	 * must be set correctly indicating the last descriptor index processed.
114012011SSriharsha.Basavapatna@Sun.COM 	 */
114112011SSriharsha.Basavapatna@Sun.COM 	if (((start != VNET_START_IDX_UNSPEC) && !(CHECK_TXI(dp, start))) ||
114212011SSriharsha.Basavapatna@Sun.COM 	    !(CHECK_TXI(dp, end))) {
114312011SSriharsha.Basavapatna@Sun.COM 		/* drop the message if invalid index */
114412011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s(%lld): Invalid Tx ack start(%d) or end(%d)\n",
114512011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id, start, end);
114612011SSriharsha.Basavapatna@Sun.COM 		return;
114712011SSriharsha.Basavapatna@Sun.COM 	}
114812011SSriharsha.Basavapatna@Sun.COM 
114912011SSriharsha.Basavapatna@Sun.COM 	/* Validate dring_ident */
115012011SSriharsha.Basavapatna@Sun.COM 	if (msg->dring_ident != ldcp->lane_out.dringp->ident) {
115112011SSriharsha.Basavapatna@Sun.COM 		/* invalid dring_ident, drop the msg */
115212011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s(%lld): Invalid dring ident 0x%x\n",
115312011SSriharsha.Basavapatna@Sun.COM 		    __func__, ldcp->ldc_id, msg->dring_ident);
115412011SSriharsha.Basavapatna@Sun.COM 		return;
115512011SSriharsha.Basavapatna@Sun.COM 	}
115612011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_acks_rcvd++;
115712011SSriharsha.Basavapatna@Sun.COM 
115812011SSriharsha.Basavapatna@Sun.COM 	if (msg->dring_process_state != VIO_DP_STOPPED) {
115912011SSriharsha.Basavapatna@Sun.COM 		/*
116012011SSriharsha.Basavapatna@Sun.COM 		 * Receiver continued processing
116112011SSriharsha.Basavapatna@Sun.COM 		 * dring after sending us the ack.
116212011SSriharsha.Basavapatna@Sun.COM 		 */
116312011SSriharsha.Basavapatna@Sun.COM 		return;
116412011SSriharsha.Basavapatna@Sun.COM 	}
116512011SSriharsha.Basavapatna@Sun.COM 
116612011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_stopped_acks_rcvd++;
116712011SSriharsha.Basavapatna@Sun.COM 
116812011SSriharsha.Basavapatna@Sun.COM 	/*
116912011SSriharsha.Basavapatna@Sun.COM 	 * Setup on_trap() protection before accessing dring shared memory area.
117012011SSriharsha.Basavapatna@Sun.COM 	 */
117112011SSriharsha.Basavapatna@Sun.COM 	rv = LDC_ON_TRAP(&otd);
117212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
117312011SSriharsha.Basavapatna@Sun.COM 		/*
117412011SSriharsha.Basavapatna@Sun.COM 		 * Data access fault occured down the code path below while
117512011SSriharsha.Basavapatna@Sun.COM 		 * accessing the descriptors. Release any locks that we might
117612011SSriharsha.Basavapatna@Sun.COM 		 * have acquired in the code below and return failure.
117712011SSriharsha.Basavapatna@Sun.COM 		 */
117812011SSriharsha.Basavapatna@Sun.COM 		if (mutex_owned(&dp->restart_lock)) {
117912011SSriharsha.Basavapatna@Sun.COM 			mutex_exit(&dp->restart_lock);
118012011SSriharsha.Basavapatna@Sun.COM 		}
118112011SSriharsha.Basavapatna@Sun.COM 		return;
118212011SSriharsha.Basavapatna@Sun.COM 	}
118312011SSriharsha.Basavapatna@Sun.COM 
118412011SSriharsha.Basavapatna@Sun.COM 	/*
118512011SSriharsha.Basavapatna@Sun.COM 	 * Determine if there are any pending tx descriptors ready to be
118612011SSriharsha.Basavapatna@Sun.COM 	 * processed by the receiver(peer) and if so, send a message to the
118712011SSriharsha.Basavapatna@Sun.COM 	 * peer to restart receiving.
118812011SSriharsha.Basavapatna@Sun.COM 	 */
118912011SSriharsha.Basavapatna@Sun.COM 	mutex_enter(&dp->restart_lock);
119012011SSriharsha.Basavapatna@Sun.COM 
119112011SSriharsha.Basavapatna@Sun.COM 	ready_txd = B_FALSE;
119212011SSriharsha.Basavapatna@Sun.COM 	txi = end;
119312011SSriharsha.Basavapatna@Sun.COM 	INCR_TXI(dp, txi);
119412011SSriharsha.Basavapatna@Sun.COM 	txdp = &pub_addr[txi];
119512011SSriharsha.Basavapatna@Sun.COM 	if (txdp->dstate == VIO_DESC_READY) {
119612011SSriharsha.Basavapatna@Sun.COM 		ready_txd = B_TRUE;
119712011SSriharsha.Basavapatna@Sun.COM 	}
119812011SSriharsha.Basavapatna@Sun.COM 
119912011SSriharsha.Basavapatna@Sun.COM 	/*
120012011SSriharsha.Basavapatna@Sun.COM 	 * We are done accessing shared memory; clear trap protection.
120112011SSriharsha.Basavapatna@Sun.COM 	 */
120212011SSriharsha.Basavapatna@Sun.COM 	(void) LDC_NO_TRAP();
120312011SSriharsha.Basavapatna@Sun.COM 
120412011SSriharsha.Basavapatna@Sun.COM 	if (ready_txd == B_FALSE) {
120512011SSriharsha.Basavapatna@Sun.COM 		/*
120612011SSriharsha.Basavapatna@Sun.COM 		 * No ready tx descriptors. Set the flag to send a message to
120712011SSriharsha.Basavapatna@Sun.COM 		 * the peer when tx descriptors are ready in transmit routine.
120812011SSriharsha.Basavapatna@Sun.COM 		 */
120912011SSriharsha.Basavapatna@Sun.COM 		dp->restart_reqd = B_TRUE;
121012950SWentao.Yang@Sun.COM 		dp->restart_peer_txi = txi;
121112011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&dp->restart_lock);
121212011SSriharsha.Basavapatna@Sun.COM 		return;
121312011SSriharsha.Basavapatna@Sun.COM 	}
121412011SSriharsha.Basavapatna@Sun.COM 
121512011SSriharsha.Basavapatna@Sun.COM 	/*
121612011SSriharsha.Basavapatna@Sun.COM 	 * We have some tx descriptors ready to be processed by the receiver.
121712011SSriharsha.Basavapatna@Sun.COM 	 * Send a dring data message to the peer to restart processing.
121812011SSriharsha.Basavapatna@Sun.COM 	 */
121912011SSriharsha.Basavapatna@Sun.COM 	dp->restart_reqd = B_FALSE;
122012011SSriharsha.Basavapatna@Sun.COM 	mutex_exit(&dp->restart_lock);
122112011SSriharsha.Basavapatna@Sun.COM 
122212011SSriharsha.Basavapatna@Sun.COM 	msg->tag.vio_msgtype = VIO_TYPE_DATA;
122312011SSriharsha.Basavapatna@Sun.COM 	msg->tag.vio_subtype = VIO_SUBTYPE_INFO;
122412011SSriharsha.Basavapatna@Sun.COM 	msg->tag.vio_subtype_env = VIO_DRING_DATA;
122512011SSriharsha.Basavapatna@Sun.COM 	msg->tag.vio_sid = ldcp->local_session;
122612011SSriharsha.Basavapatna@Sun.COM 	msg->dring_ident = ldcp->lane_out.dringp->ident;
122712011SSriharsha.Basavapatna@Sun.COM 	msg->start_idx = txi;
122812011SSriharsha.Basavapatna@Sun.COM 	msg->end_idx = -1;
122912011SSriharsha.Basavapatna@Sun.COM 	rv = vsw_send_msg_shm(ldcp, (void *)msg,
123012011SSriharsha.Basavapatna@Sun.COM 	    sizeof (vio_dring_msg_t), B_FALSE);
123112011SSriharsha.Basavapatna@Sun.COM 	statsp->dring_data_msgs_sent++;
123212011SSriharsha.Basavapatna@Sun.COM 	if (rv != 0) {
123312011SSriharsha.Basavapatna@Sun.COM 		mutex_enter(&dp->restart_lock);
123412011SSriharsha.Basavapatna@Sun.COM 		dp->restart_reqd = B_TRUE;
123512011SSriharsha.Basavapatna@Sun.COM 		mutex_exit(&dp->restart_lock);
123612011SSriharsha.Basavapatna@Sun.COM 	}
123712011SSriharsha.Basavapatna@Sun.COM 
123812011SSriharsha.Basavapatna@Sun.COM 	if (rv == ECONNRESET) {
123912011SSriharsha.Basavapatna@Sun.COM 		vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
124012011SSriharsha.Basavapatna@Sun.COM 	}
124112011SSriharsha.Basavapatna@Sun.COM }
124212011SSriharsha.Basavapatna@Sun.COM 
124312011SSriharsha.Basavapatna@Sun.COM /*
124412011SSriharsha.Basavapatna@Sun.COM  * Send dring data msgs (info/ack/nack) over LDC.
124512011SSriharsha.Basavapatna@Sun.COM  */
124612011SSriharsha.Basavapatna@Sun.COM int
vsw_send_msg_shm(vsw_ldc_t * ldcp,void * msgp,int size,boolean_t handle_reset)124712011SSriharsha.Basavapatna@Sun.COM vsw_send_msg_shm(vsw_ldc_t *ldcp, void *msgp, int size, boolean_t handle_reset)
124812011SSriharsha.Basavapatna@Sun.COM {
124912011SSriharsha.Basavapatna@Sun.COM 	int			rv;
125012011SSriharsha.Basavapatna@Sun.COM 	int			retries = vsw_wretries;
125112011SSriharsha.Basavapatna@Sun.COM 	size_t			msglen = size;
125212011SSriharsha.Basavapatna@Sun.COM 	vsw_t			*vswp = ldcp->ldc_vswp;
125312011SSriharsha.Basavapatna@Sun.COM 	vio_dring_msg_t		*dmsg = (vio_dring_msg_t *)msgp;
125412011SSriharsha.Basavapatna@Sun.COM 
125512011SSriharsha.Basavapatna@Sun.COM 	D1(vswp, "vsw_send_msg (%lld) enter : sending %d bytes",
125612011SSriharsha.Basavapatna@Sun.COM 	    ldcp->ldc_id, size);
125712011SSriharsha.Basavapatna@Sun.COM 
125812011SSriharsha.Basavapatna@Sun.COM 	dmsg->seq_num = atomic_inc_32_nv(&ldcp->dringdata_msgid);
125912011SSriharsha.Basavapatna@Sun.COM 
126012011SSriharsha.Basavapatna@Sun.COM 	do {
126112011SSriharsha.Basavapatna@Sun.COM 		msglen = size;
126212011SSriharsha.Basavapatna@Sun.COM 		rv = ldc_write(ldcp->ldc_handle, (caddr_t)msgp, &msglen);
126312011SSriharsha.Basavapatna@Sun.COM 	} while (rv == EWOULDBLOCK && --retries > 0);
126412011SSriharsha.Basavapatna@Sun.COM 
126512011SSriharsha.Basavapatna@Sun.COM 	if ((rv != 0) || (msglen != size)) {
126612011SSriharsha.Basavapatna@Sun.COM 		DERR(vswp, "vsw_send_msg_shm:ldc_write failed: "
126712011SSriharsha.Basavapatna@Sun.COM 		    "chan(%lld) rv(%d) size (%d) msglen(%d)\n",
126812011SSriharsha.Basavapatna@Sun.COM 		    ldcp->ldc_id, rv, size, msglen);
126912011SSriharsha.Basavapatna@Sun.COM 		ldcp->ldc_stats.oerrors++;
127012011SSriharsha.Basavapatna@Sun.COM 	}
127112011SSriharsha.Basavapatna@Sun.COM 
127212011SSriharsha.Basavapatna@Sun.COM 	/*
127312011SSriharsha.Basavapatna@Sun.COM 	 * If channel has been reset we either handle it here or
127412011SSriharsha.Basavapatna@Sun.COM 	 * simply report back that it has been reset and let caller
127512011SSriharsha.Basavapatna@Sun.COM 	 * decide what to do.
127612011SSriharsha.Basavapatna@Sun.COM 	 */
127712011SSriharsha.Basavapatna@Sun.COM 	if (rv == ECONNRESET) {
127812011SSriharsha.Basavapatna@Sun.COM 		DWARN(vswp, "%s (%lld) channel reset", __func__, ldcp->ldc_id);
127912011SSriharsha.Basavapatna@Sun.COM 
128012011SSriharsha.Basavapatna@Sun.COM 		if (handle_reset) {
128112011SSriharsha.Basavapatna@Sun.COM 			vsw_process_conn_evt(ldcp, VSW_CONN_RESET);
128212011SSriharsha.Basavapatna@Sun.COM 		}
128312011SSriharsha.Basavapatna@Sun.COM 	}
128412011SSriharsha.Basavapatna@Sun.COM 
128512011SSriharsha.Basavapatna@Sun.COM 	return (rv);
128612011SSriharsha.Basavapatna@Sun.COM }
1287