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