xref: /illumos-gate/usr/src/uts/common/io/sfxge/sfxge_tx.c (revision 49ef7e0638c8b771d8a136eae78b1c0f99acc8e0)
1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore  * Copyright (c) 2008-2016 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore  * All rights reserved.
4*49ef7e06SGarrett D'Amore  *
5*49ef7e06SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore  * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore  *
8*49ef7e06SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore  *    and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore  *
14*49ef7e06SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore  *
26*49ef7e06SGarrett D'Amore  * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore  * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore  * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore  */
30*49ef7e06SGarrett D'Amore 
31*49ef7e06SGarrett D'Amore #include <sys/types.h>
32*49ef7e06SGarrett D'Amore #include <sys/sysmacros.h>
33*49ef7e06SGarrett D'Amore #include <sys/ddi.h>
34*49ef7e06SGarrett D'Amore #include <sys/sunddi.h>
35*49ef7e06SGarrett D'Amore #include <sys/atomic.h>
36*49ef7e06SGarrett D'Amore #include <sys/stream.h>
37*49ef7e06SGarrett D'Amore #include <sys/strsun.h>
38*49ef7e06SGarrett D'Amore #include <sys/strsubr.h>
39*49ef7e06SGarrett D'Amore #include <sys/pattr.h>
40*49ef7e06SGarrett D'Amore #include <sys/cpu.h>
41*49ef7e06SGarrett D'Amore 
42*49ef7e06SGarrett D'Amore #include <sys/ethernet.h>
43*49ef7e06SGarrett D'Amore #include <inet/ip.h>
44*49ef7e06SGarrett D'Amore 
45*49ef7e06SGarrett D'Amore #include <netinet/in.h>
46*49ef7e06SGarrett D'Amore #include <netinet/ip.h>
47*49ef7e06SGarrett D'Amore #include <netinet/tcp.h>
48*49ef7e06SGarrett D'Amore 
49*49ef7e06SGarrett D'Amore #include "sfxge.h"
50*49ef7e06SGarrett D'Amore 
51*49ef7e06SGarrett D'Amore #include "efx.h"
52*49ef7e06SGarrett D'Amore 
53*49ef7e06SGarrett D'Amore /* TXQ flush response timeout (in microseconds) */
54*49ef7e06SGarrett D'Amore #define	SFXGE_TX_QFLUSH_USEC	(2000000)
55*49ef7e06SGarrett D'Amore 
56*49ef7e06SGarrett D'Amore /* See sfxge.conf.private for descriptions */
57*49ef7e06SGarrett D'Amore #define	SFXGE_TX_DPL_GET_PKT_LIMIT_DEFAULT 4096
58*49ef7e06SGarrett D'Amore #define	SFXGE_TX_DPL_PUT_PKT_LIMIT_DEFAULT 256
59*49ef7e06SGarrett D'Amore 
60*49ef7e06SGarrett D'Amore 
61*49ef7e06SGarrett D'Amore /* Transmit buffer DMA attributes */
62*49ef7e06SGarrett D'Amore static ddi_device_acc_attr_t sfxge_tx_buffer_devacc = {
63*49ef7e06SGarrett D'Amore 
64*49ef7e06SGarrett D'Amore 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
65*49ef7e06SGarrett D'Amore 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
66*49ef7e06SGarrett D'Amore 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
67*49ef7e06SGarrett D'Amore };
68*49ef7e06SGarrett D'Amore 
69*49ef7e06SGarrett D'Amore static ddi_dma_attr_t sfxge_tx_buffer_dma_attr = {
70*49ef7e06SGarrett D'Amore 	DMA_ATTR_V0,		/* dma_attr_version	*/
71*49ef7e06SGarrett D'Amore 	0,			/* dma_attr_addr_lo	*/
72*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_addr_hi	*/
73*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_count_max	*/
74*49ef7e06SGarrett D'Amore 	SFXGE_TX_BUFFER_SIZE,	/* dma_attr_align	*/
75*49ef7e06SGarrett D'Amore 	0xffffffff,		/* dma_attr_burstsizes	*/
76*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_minxfer	*/
77*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_maxxfer	*/
78*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_seg		*/
79*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_sgllen	*/
80*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_granular	*/
81*49ef7e06SGarrett D'Amore 	0			/* dma_attr_flags	*/
82*49ef7e06SGarrett D'Amore };
83*49ef7e06SGarrett D'Amore 
84*49ef7e06SGarrett D'Amore /* Transmit mapping DMA attributes */
85*49ef7e06SGarrett D'Amore static ddi_dma_attr_t sfxge_tx_mapping_dma_attr = {
86*49ef7e06SGarrett D'Amore 	DMA_ATTR_V0,		/* dma_attr_version	*/
87*49ef7e06SGarrett D'Amore 	0,			/* dma_attr_addr_lo	*/
88*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_addr_hi	*/
89*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_count_max	*/
90*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_align	*/
91*49ef7e06SGarrett D'Amore 	0xffffffff,		/* dma_attr_burstsizes	*/
92*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_minxfer	*/
93*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_maxxfer	*/
94*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_seg		*/
95*49ef7e06SGarrett D'Amore 	0x7fffffff,		/* dma_attr_sgllen	*/
96*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_granular	*/
97*49ef7e06SGarrett D'Amore 	0			/* dma_attr_flags	*/
98*49ef7e06SGarrett D'Amore };
99*49ef7e06SGarrett D'Amore 
100*49ef7e06SGarrett D'Amore /* Transmit queue DMA attributes */
101*49ef7e06SGarrett D'Amore static ddi_device_acc_attr_t sfxge_txq_devacc = {
102*49ef7e06SGarrett D'Amore 
103*49ef7e06SGarrett D'Amore 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
104*49ef7e06SGarrett D'Amore 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
105*49ef7e06SGarrett D'Amore 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
106*49ef7e06SGarrett D'Amore };
107*49ef7e06SGarrett D'Amore 
108*49ef7e06SGarrett D'Amore static ddi_dma_attr_t sfxge_txq_dma_attr = {
109*49ef7e06SGarrett D'Amore 	DMA_ATTR_V0,		/* dma_attr_version	*/
110*49ef7e06SGarrett D'Amore 	0,			/* dma_attr_addr_lo	*/
111*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_addr_hi	*/
112*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_count_max	*/
113*49ef7e06SGarrett D'Amore 	EFX_BUF_SIZE,		/* dma_attr_align	*/
114*49ef7e06SGarrett D'Amore 	0xffffffff,		/* dma_attr_burstsizes	*/
115*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_minxfer	*/
116*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_maxxfer	*/
117*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_seg		*/
118*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_sgllen	*/
119*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_granular	*/
120*49ef7e06SGarrett D'Amore 	0			/* dma_attr_flags	*/
121*49ef7e06SGarrett D'Amore };
122*49ef7e06SGarrett D'Amore 
123*49ef7e06SGarrett D'Amore 
124*49ef7e06SGarrett D'Amore /*
125*49ef7e06SGarrett D'Amore  * A sfxge_tx_qdpl_swizzle() can happen when the DPL get list is one packet
126*49ef7e06SGarrett D'Amore  * under the limit, and must move all packets from the DPL put->get list
127*49ef7e06SGarrett D'Amore  * Hence this is the real maximum length of the TX DPL get list.
128*49ef7e06SGarrett D'Amore  */
129*49ef7e06SGarrett D'Amore static int
sfxge_tx_dpl_get_pkt_max(sfxge_txq_t * stp)130*49ef7e06SGarrett D'Amore sfxge_tx_dpl_get_pkt_max(sfxge_txq_t *stp)
131*49ef7e06SGarrett D'Amore {
132*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
133*49ef7e06SGarrett D'Amore 	return (stdp->get_pkt_limit + stdp->put_pkt_limit - 1);
134*49ef7e06SGarrett D'Amore }
135*49ef7e06SGarrett D'Amore 
136*49ef7e06SGarrett D'Amore 
137*49ef7e06SGarrett D'Amore static int
sfxge_tx_packet_ctor(void * buf,void * arg,int kmflags)138*49ef7e06SGarrett D'Amore sfxge_tx_packet_ctor(void *buf, void *arg, int kmflags)
139*49ef7e06SGarrett D'Amore {
140*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg, kmflags))
141*49ef7e06SGarrett D'Amore 
142*49ef7e06SGarrett D'Amore 	bzero(buf, sizeof (sfxge_tx_packet_t));
143*49ef7e06SGarrett D'Amore 
144*49ef7e06SGarrett D'Amore 	return (0);
145*49ef7e06SGarrett D'Amore }
146*49ef7e06SGarrett D'Amore 
147*49ef7e06SGarrett D'Amore static void
sfxge_tx_packet_dtor(void * buf,void * arg)148*49ef7e06SGarrett D'Amore sfxge_tx_packet_dtor(void *buf, void *arg)
149*49ef7e06SGarrett D'Amore {
150*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp = buf;
151*49ef7e06SGarrett D'Amore 
152*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg))
153*49ef7e06SGarrett D'Amore 
154*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stpp, sfxge_tx_packet_t);
155*49ef7e06SGarrett D'Amore }
156*49ef7e06SGarrett D'Amore 
157*49ef7e06SGarrett D'Amore static int
sfxge_tx_buffer_ctor(void * buf,void * arg,int kmflags)158*49ef7e06SGarrett D'Amore sfxge_tx_buffer_ctor(void *buf, void *arg, int kmflags)
159*49ef7e06SGarrett D'Amore {
160*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp = buf;
161*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
162*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_attr_t dma_attr;
163*49ef7e06SGarrett D'Amore 	int rc;
164*49ef7e06SGarrett D'Amore 
165*49ef7e06SGarrett D'Amore 	bzero(buf, sizeof (sfxge_tx_buffer_t));
166*49ef7e06SGarrett D'Amore 
167*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dip	 = sp->s_dip;
168*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dattrp	 = &sfxge_tx_buffer_dma_attr;
169*49ef7e06SGarrett D'Amore 	dma_attr.sdba_callback	 = ((kmflags == KM_SLEEP) ?
170*49ef7e06SGarrett D'Amore 	    DDI_DMA_SLEEP : DDI_DMA_DONTWAIT);
171*49ef7e06SGarrett D'Amore 	dma_attr.sdba_length	 = SFXGE_TX_BUFFER_SIZE;
172*49ef7e06SGarrett D'Amore 	dma_attr.sdba_memflags	 = DDI_DMA_STREAMING;
173*49ef7e06SGarrett D'Amore 	dma_attr.sdba_devaccp	 = &sfxge_tx_buffer_devacc;
174*49ef7e06SGarrett D'Amore 	dma_attr.sdba_bindflags	 = DDI_DMA_WRITE | DDI_DMA_STREAMING;
175*49ef7e06SGarrett D'Amore 	dma_attr.sdba_maxcookies = 1;
176*49ef7e06SGarrett D'Amore 	dma_attr.sdba_zeroinit	 = B_FALSE;
177*49ef7e06SGarrett D'Amore 
178*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_dma_buffer_create(&(stbp->stb_esm), &dma_attr)) != 0)
179*49ef7e06SGarrett D'Amore 		goto fail1;
180*49ef7e06SGarrett D'Amore 
181*49ef7e06SGarrett D'Amore 	return (0);
182*49ef7e06SGarrett D'Amore 
183*49ef7e06SGarrett D'Amore fail1:
184*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
185*49ef7e06SGarrett D'Amore 
186*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stbp, sfxge_tx_buffer_t);
187*49ef7e06SGarrett D'Amore 
188*49ef7e06SGarrett D'Amore 	return (-1);
189*49ef7e06SGarrett D'Amore }
190*49ef7e06SGarrett D'Amore 
191*49ef7e06SGarrett D'Amore static void
sfxge_tx_buffer_dtor(void * buf,void * arg)192*49ef7e06SGarrett D'Amore sfxge_tx_buffer_dtor(void *buf, void *arg)
193*49ef7e06SGarrett D'Amore {
194*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp = buf;
195*49ef7e06SGarrett D'Amore 
196*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg))
197*49ef7e06SGarrett D'Amore 
198*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(&(stbp->stb_esm));
199*49ef7e06SGarrett D'Amore 
200*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stbp, sfxge_tx_buffer_t);
201*49ef7e06SGarrett D'Amore }
202*49ef7e06SGarrett D'Amore 
203*49ef7e06SGarrett D'Amore static int
sfxge_tx_mapping_ctor(void * buf,void * arg,int kmflags)204*49ef7e06SGarrett D'Amore sfxge_tx_mapping_ctor(void *buf, void *arg, int kmflags)
205*49ef7e06SGarrett D'Amore {
206*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp = buf;
207*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
208*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
209*49ef7e06SGarrett D'Amore 	int rc;
210*49ef7e06SGarrett D'Amore 
211*49ef7e06SGarrett D'Amore 	bzero(buf, sizeof (sfxge_tx_mapping_t));
212*49ef7e06SGarrett D'Amore 
213*49ef7e06SGarrett D'Amore 	stmp->stm_sp = sp;
214*49ef7e06SGarrett D'Amore 
215*49ef7e06SGarrett D'Amore 	/* Allocate DMA handle */
216*49ef7e06SGarrett D'Amore 	rc = ddi_dma_alloc_handle(dip, &sfxge_tx_mapping_dma_attr,
217*49ef7e06SGarrett D'Amore 	    (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT,
218*49ef7e06SGarrett D'Amore 	    NULL, &(stmp->stm_dma_handle));
219*49ef7e06SGarrett D'Amore 	if (rc != DDI_SUCCESS)
220*49ef7e06SGarrett D'Amore 		goto fail1;
221*49ef7e06SGarrett D'Amore 
222*49ef7e06SGarrett D'Amore 	return (0);
223*49ef7e06SGarrett D'Amore 
224*49ef7e06SGarrett D'Amore fail1:
225*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
226*49ef7e06SGarrett D'Amore 
227*49ef7e06SGarrett D'Amore 	stmp->stm_sp = NULL;
228*49ef7e06SGarrett D'Amore 
229*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stmp, sfxge_tx_mapping_t);
230*49ef7e06SGarrett D'Amore 
231*49ef7e06SGarrett D'Amore 	return (-1);
232*49ef7e06SGarrett D'Amore }
233*49ef7e06SGarrett D'Amore 
234*49ef7e06SGarrett D'Amore static void
sfxge_tx_mapping_dtor(void * buf,void * arg)235*49ef7e06SGarrett D'Amore sfxge_tx_mapping_dtor(void *buf, void *arg)
236*49ef7e06SGarrett D'Amore {
237*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp = buf;
238*49ef7e06SGarrett D'Amore 
239*49ef7e06SGarrett D'Amore 	ASSERT3P(stmp->stm_sp, ==, arg);
240*49ef7e06SGarrett D'Amore 
241*49ef7e06SGarrett D'Amore 	/* Free the DMA handle */
242*49ef7e06SGarrett D'Amore 	ddi_dma_free_handle(&(stmp->stm_dma_handle));
243*49ef7e06SGarrett D'Amore 	stmp->stm_dma_handle = NULL;
244*49ef7e06SGarrett D'Amore 
245*49ef7e06SGarrett D'Amore 	stmp->stm_sp = NULL;
246*49ef7e06SGarrett D'Amore 
247*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stmp, sfxge_tx_mapping_t);
248*49ef7e06SGarrett D'Amore }
249*49ef7e06SGarrett D'Amore 
250*49ef7e06SGarrett D'Amore static int
sfxge_tx_qctor(void * buf,void * arg,int kmflags)251*49ef7e06SGarrett D'Amore sfxge_tx_qctor(void *buf, void *arg, int kmflags)
252*49ef7e06SGarrett D'Amore {
253*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = buf;
254*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp = &(stp->st_mem);
255*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
256*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_attr_t dma_attr;
257*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp;
258*49ef7e06SGarrett D'Amore 	int rc;
259*49ef7e06SGarrett D'Amore 
260*49ef7e06SGarrett D'Amore 	/* Compile-time structure layout checks */
261*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (stp->__st_u1.__st_s1) <=
262*49ef7e06SGarrett D'Amore 	    sizeof (stp->__st_u1.__st_pad));
263*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (stp->__st_u2.__st_s2) <=
264*49ef7e06SGarrett D'Amore 	    sizeof (stp->__st_u2.__st_pad));
265*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (stp->__st_u3.__st_s3) <=
266*49ef7e06SGarrett D'Amore 	    sizeof (stp->__st_u3.__st_pad));
267*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (stp->__st_u4.__st_s4) <=
268*49ef7e06SGarrett D'Amore 	    sizeof (stp->__st_u4.__st_pad));
269*49ef7e06SGarrett D'Amore 
270*49ef7e06SGarrett D'Amore 	bzero(buf, sizeof (sfxge_txq_t));
271*49ef7e06SGarrett D'Amore 
272*49ef7e06SGarrett D'Amore 	stp->st_sp = sp;
273*49ef7e06SGarrett D'Amore 
274*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dip	 = sp->s_dip;
275*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dattrp	 = &sfxge_txq_dma_attr;
276*49ef7e06SGarrett D'Amore 	dma_attr.sdba_callback	 = DDI_DMA_SLEEP;
277*49ef7e06SGarrett D'Amore 	dma_attr.sdba_length	 = EFX_TXQ_SIZE(SFXGE_TX_NDESCS);
278*49ef7e06SGarrett D'Amore 	dma_attr.sdba_memflags	 = DDI_DMA_CONSISTENT;
279*49ef7e06SGarrett D'Amore 	dma_attr.sdba_devaccp	 = &sfxge_txq_devacc;
280*49ef7e06SGarrett D'Amore 	dma_attr.sdba_bindflags	 = DDI_DMA_READ | DDI_DMA_CONSISTENT;
281*49ef7e06SGarrett D'Amore 	dma_attr.sdba_maxcookies = EFX_TXQ_NBUFS(SFXGE_TX_NDESCS);
282*49ef7e06SGarrett D'Amore 	dma_attr.sdba_zeroinit	 = B_FALSE;
283*49ef7e06SGarrett D'Amore 
284*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
285*49ef7e06SGarrett D'Amore 		goto fail1;
286*49ef7e06SGarrett D'Amore 
287*49ef7e06SGarrett D'Amore 	/* Allocate some buffer table entries */
288*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_sram_buf_tbl_alloc(sp, EFX_TXQ_NBUFS(SFXGE_TX_NDESCS),
289*49ef7e06SGarrett D'Amore 	    &(stp->st_id))) != 0)
290*49ef7e06SGarrett D'Amore 		goto fail2;
291*49ef7e06SGarrett D'Amore 
292*49ef7e06SGarrett D'Amore 	/* Allocate the descriptor array */
293*49ef7e06SGarrett D'Amore 	if ((stp->st_eb = kmem_zalloc(sizeof (efx_buffer_t) *
294*49ef7e06SGarrett D'Amore 	    EFX_TXQ_LIMIT(SFXGE_TX_NDESCS), kmflags)) == NULL) {
295*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
296*49ef7e06SGarrett D'Amore 		goto fail3;
297*49ef7e06SGarrett D'Amore 	}
298*49ef7e06SGarrett D'Amore 
299*49ef7e06SGarrett D'Amore 	/* Allocate the context arrays */
300*49ef7e06SGarrett D'Amore 	if ((stp->st_stmp = kmem_zalloc(sizeof (sfxge_tx_mapping_t *) *
301*49ef7e06SGarrett D'Amore 	    SFXGE_TX_NDESCS, kmflags)) == NULL) {
302*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
303*49ef7e06SGarrett D'Amore 		goto fail4;
304*49ef7e06SGarrett D'Amore 	}
305*49ef7e06SGarrett D'Amore 
306*49ef7e06SGarrett D'Amore 	if ((stp->st_stbp = kmem_zalloc(sizeof (sfxge_tx_buffer_t *) *
307*49ef7e06SGarrett D'Amore 	    SFXGE_TX_NDESCS, kmflags)) == NULL) {
308*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
309*49ef7e06SGarrett D'Amore 		goto fail5;
310*49ef7e06SGarrett D'Amore 	}
311*49ef7e06SGarrett D'Amore 
312*49ef7e06SGarrett D'Amore 	if ((stp->st_mp = kmem_zalloc(sizeof (mblk_t *) *
313*49ef7e06SGarrett D'Amore 	    SFXGE_TX_NDESCS, kmflags)) == NULL) {
314*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
315*49ef7e06SGarrett D'Amore 		goto fail6;
316*49ef7e06SGarrett D'Amore 	}
317*49ef7e06SGarrett D'Amore 
318*49ef7e06SGarrett D'Amore 	/* Initialize the deferred packet list */
319*49ef7e06SGarrett D'Amore 	stdp = &(stp->st_dpl);
320*49ef7e06SGarrett D'Amore 	stdp->std_getp = &(stdp->std_get);
321*49ef7e06SGarrett D'Amore 
322*49ef7e06SGarrett D'Amore 	stp->st_unblock = SFXGE_TXQ_NOT_BLOCKED;
323*49ef7e06SGarrett D'Amore 
324*49ef7e06SGarrett D'Amore 	return (0);
325*49ef7e06SGarrett D'Amore 
326*49ef7e06SGarrett D'Amore fail6:
327*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail6);
328*49ef7e06SGarrett D'Amore 
329*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_stbp, sizeof (sfxge_tx_buffer_t *) * SFXGE_TX_NDESCS);
330*49ef7e06SGarrett D'Amore 	stp->st_stbp = NULL;
331*49ef7e06SGarrett D'Amore 
332*49ef7e06SGarrett D'Amore fail5:
333*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail5);
334*49ef7e06SGarrett D'Amore 
335*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_stmp,
336*49ef7e06SGarrett D'Amore 	    sizeof (sfxge_tx_mapping_t *) * SFXGE_TX_NDESCS);
337*49ef7e06SGarrett D'Amore 	stp->st_stmp = NULL;
338*49ef7e06SGarrett D'Amore 
339*49ef7e06SGarrett D'Amore fail4:
340*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
341*49ef7e06SGarrett D'Amore 
342*49ef7e06SGarrett D'Amore 	/* Free the descriptor array */
343*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_eb, sizeof (efx_buffer_t) *
344*49ef7e06SGarrett D'Amore 	    EFX_TXQ_LIMIT(SFXGE_TX_NDESCS));
345*49ef7e06SGarrett D'Amore 	stp->st_eb = NULL;
346*49ef7e06SGarrett D'Amore 
347*49ef7e06SGarrett D'Amore fail3:
348*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
349*49ef7e06SGarrett D'Amore 
350*49ef7e06SGarrett D'Amore 	/* Free the buffer table entries */
351*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_free(sp, stp->st_id, EFX_TXQ_NBUFS(SFXGE_TX_NDESCS));
352*49ef7e06SGarrett D'Amore 	stp->st_id = 0;
353*49ef7e06SGarrett D'Amore 
354*49ef7e06SGarrett D'Amore fail2:
355*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
356*49ef7e06SGarrett D'Amore 
357*49ef7e06SGarrett D'Amore 	/* Tear down DMA setup */
358*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(esmp);
359*49ef7e06SGarrett D'Amore 
360*49ef7e06SGarrett D'Amore fail1:
361*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
362*49ef7e06SGarrett D'Amore 
363*49ef7e06SGarrett D'Amore 	stp->st_sp = NULL;
364*49ef7e06SGarrett D'Amore 
365*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stp, sfxge_txq_t);
366*49ef7e06SGarrett D'Amore 
367*49ef7e06SGarrett D'Amore 	return (-1);
368*49ef7e06SGarrett D'Amore }
369*49ef7e06SGarrett D'Amore 
370*49ef7e06SGarrett D'Amore static void
sfxge_tx_qdtor(void * buf,void * arg)371*49ef7e06SGarrett D'Amore sfxge_tx_qdtor(void *buf, void *arg)
372*49ef7e06SGarrett D'Amore {
373*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = buf;
374*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp = &(stp->st_mem);
375*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
376*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp;
377*49ef7e06SGarrett D'Amore 
378*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg))
379*49ef7e06SGarrett D'Amore 
380*49ef7e06SGarrett D'Amore 	stp->st_unblock = 0;
381*49ef7e06SGarrett D'Amore 
382*49ef7e06SGarrett D'Amore 	/* Tear down the deferred packet list */
383*49ef7e06SGarrett D'Amore 	stdp = &(stp->st_dpl);
384*49ef7e06SGarrett D'Amore 	ASSERT3P(stdp->std_getp, ==, &(stdp->std_get));
385*49ef7e06SGarrett D'Amore 	stdp->std_getp = NULL;
386*49ef7e06SGarrett D'Amore 
387*49ef7e06SGarrett D'Amore 	/* Free the context arrays */
388*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_mp, sizeof (mblk_t *) * SFXGE_TX_NDESCS);
389*49ef7e06SGarrett D'Amore 	stp->st_mp = NULL;
390*49ef7e06SGarrett D'Amore 
391*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_stbp, sizeof (sfxge_tx_buffer_t *) * SFXGE_TX_NDESCS);
392*49ef7e06SGarrett D'Amore 	stp->st_stbp = NULL;
393*49ef7e06SGarrett D'Amore 
394*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_stmp,
395*49ef7e06SGarrett D'Amore 	    sizeof (sfxge_tx_mapping_t *) * SFXGE_TX_NDESCS);
396*49ef7e06SGarrett D'Amore 	stp->st_stmp = NULL;
397*49ef7e06SGarrett D'Amore 
398*49ef7e06SGarrett D'Amore 	/* Free the descriptor array */
399*49ef7e06SGarrett D'Amore 	kmem_free(stp->st_eb, sizeof (efx_buffer_t) *
400*49ef7e06SGarrett D'Amore 	    EFX_TXQ_LIMIT(SFXGE_TX_NDESCS));
401*49ef7e06SGarrett D'Amore 	stp->st_eb = NULL;
402*49ef7e06SGarrett D'Amore 
403*49ef7e06SGarrett D'Amore 	/* Free the buffer table entries */
404*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_free(sp, stp->st_id, EFX_TXQ_NBUFS(SFXGE_TX_NDESCS));
405*49ef7e06SGarrett D'Amore 	stp->st_id = 0;
406*49ef7e06SGarrett D'Amore 
407*49ef7e06SGarrett D'Amore 	/* Tear down dma setup */
408*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(esmp);
409*49ef7e06SGarrett D'Amore 
410*49ef7e06SGarrett D'Amore 	stp->st_sp = NULL;
411*49ef7e06SGarrett D'Amore 
412*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(stp, sfxge_txq_t);
413*49ef7e06SGarrett D'Amore }
414*49ef7e06SGarrett D'Amore 
415*49ef7e06SGarrett D'Amore static void
sfxge_tx_packet_destroy(sfxge_t * sp,sfxge_tx_packet_t * stpp)416*49ef7e06SGarrett D'Amore sfxge_tx_packet_destroy(sfxge_t *sp, sfxge_tx_packet_t *stpp)
417*49ef7e06SGarrett D'Amore {
418*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_tpc, stpp);
419*49ef7e06SGarrett D'Amore }
420*49ef7e06SGarrett D'Amore 
421*49ef7e06SGarrett D'Amore static sfxge_tx_packet_t *
sfxge_tx_packet_create(sfxge_t * sp)422*49ef7e06SGarrett D'Amore sfxge_tx_packet_create(sfxge_t *sp)
423*49ef7e06SGarrett D'Amore {
424*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
425*49ef7e06SGarrett D'Amore 
426*49ef7e06SGarrett D'Amore 	stpp = kmem_cache_alloc(sp->s_tpc, KM_NOSLEEP);
427*49ef7e06SGarrett D'Amore 
428*49ef7e06SGarrett D'Amore 	return (stpp);
429*49ef7e06SGarrett D'Amore }
430*49ef7e06SGarrett D'Amore 
431*49ef7e06SGarrett D'Amore static inline int
sfxge_tx_qfpp_put(sfxge_txq_t * stp,sfxge_tx_packet_t * stpp)432*49ef7e06SGarrett D'Amore sfxge_tx_qfpp_put(sfxge_txq_t *stp, sfxge_tx_packet_t *stpp)
433*49ef7e06SGarrett D'Amore {
434*49ef7e06SGarrett D'Amore 	sfxge_tx_fpp_t *stfp = &(stp->st_fpp);
435*49ef7e06SGarrett D'Amore 
436*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
437*49ef7e06SGarrett D'Amore 
438*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp->stp_next, ==, NULL);
439*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp->stp_mp, ==, NULL);
440*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp->stp_etherhp, ==, NULL);
441*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp->stp_iphp, ==, NULL);
442*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp->stp_thp, ==, NULL);
443*49ef7e06SGarrett D'Amore 	ASSERT3U(stpp->stp_off, ==, 0);
444*49ef7e06SGarrett D'Amore 	ASSERT3U(stpp->stp_size, ==, 0);
445*49ef7e06SGarrett D'Amore 	ASSERT3U(stpp->stp_mss, ==, 0);
446*49ef7e06SGarrett D'Amore 	ASSERT3U(stpp->stp_dpl_put_len, ==, 0);
447*49ef7e06SGarrett D'Amore 
448*49ef7e06SGarrett D'Amore 	if (stfp->stf_count < SFXGE_TX_FPP_MAX) {
449*49ef7e06SGarrett D'Amore 		/* Add to the start of the list */
450*49ef7e06SGarrett D'Amore 		stpp->stp_next = stfp->stf_stpp;
451*49ef7e06SGarrett D'Amore 		stfp->stf_stpp = stpp;
452*49ef7e06SGarrett D'Amore 		stfp->stf_count++;
453*49ef7e06SGarrett D'Amore 
454*49ef7e06SGarrett D'Amore 		return (0);
455*49ef7e06SGarrett D'Amore 	}
456*49ef7e06SGarrett D'Amore 
457*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fpp_full);
458*49ef7e06SGarrett D'Amore 	return (ENOSPC);
459*49ef7e06SGarrett D'Amore }
460*49ef7e06SGarrett D'Amore 
461*49ef7e06SGarrett D'Amore static inline sfxge_tx_packet_t *
sfxge_tx_qfpp_get(sfxge_txq_t * stp)462*49ef7e06SGarrett D'Amore sfxge_tx_qfpp_get(sfxge_txq_t *stp)
463*49ef7e06SGarrett D'Amore {
464*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
465*49ef7e06SGarrett D'Amore 	sfxge_tx_fpp_t *stfp = &(stp->st_fpp);
466*49ef7e06SGarrett D'Amore 
467*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
468*49ef7e06SGarrett D'Amore 
469*49ef7e06SGarrett D'Amore 	stpp = stfp->stf_stpp;
470*49ef7e06SGarrett D'Amore 	if (stpp == NULL) {
471*49ef7e06SGarrett D'Amore 		ASSERT3U(stfp->stf_count, ==, 0);
472*49ef7e06SGarrett D'Amore 		return (NULL);
473*49ef7e06SGarrett D'Amore 	}
474*49ef7e06SGarrett D'Amore 
475*49ef7e06SGarrett D'Amore 	/* Remove item from the head of the list */
476*49ef7e06SGarrett D'Amore 	stfp->stf_stpp = stpp->stp_next;
477*49ef7e06SGarrett D'Amore 	stpp->stp_next = NULL;
478*49ef7e06SGarrett D'Amore 
479*49ef7e06SGarrett D'Amore 	ASSERT3U(stfp->stf_count, >, 0);
480*49ef7e06SGarrett D'Amore 	stfp->stf_count--;
481*49ef7e06SGarrett D'Amore 
482*49ef7e06SGarrett D'Amore 	if (stfp->stf_count != 0) {
483*49ef7e06SGarrett D'Amore 		ASSERT(stfp->stf_stpp != NULL);
484*49ef7e06SGarrett D'Amore 		prefetch_read_many(stfp->stf_stpp);
485*49ef7e06SGarrett D'Amore 	}
486*49ef7e06SGarrett D'Amore 	return (stpp);
487*49ef7e06SGarrett D'Amore }
488*49ef7e06SGarrett D'Amore 
489*49ef7e06SGarrett D'Amore static void
sfxge_tx_qfpp_empty(sfxge_txq_t * stp)490*49ef7e06SGarrett D'Amore sfxge_tx_qfpp_empty(sfxge_txq_t *stp)
491*49ef7e06SGarrett D'Amore {
492*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
493*49ef7e06SGarrett D'Amore 	sfxge_tx_fpp_t *stfp = &(stp->st_fpp);
494*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
495*49ef7e06SGarrett D'Amore 
496*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
497*49ef7e06SGarrett D'Amore 
498*49ef7e06SGarrett D'Amore 	stpp = stfp->stf_stpp;
499*49ef7e06SGarrett D'Amore 	stfp->stf_stpp = NULL;
500*49ef7e06SGarrett D'Amore 
501*49ef7e06SGarrett D'Amore 	while (stpp != NULL) {
502*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_t *next;
503*49ef7e06SGarrett D'Amore 
504*49ef7e06SGarrett D'Amore 		next = stpp->stp_next;
505*49ef7e06SGarrett D'Amore 		stpp->stp_next = NULL;
506*49ef7e06SGarrett D'Amore 
507*49ef7e06SGarrett D'Amore 		ASSERT3U(stfp->stf_count, >, 0);
508*49ef7e06SGarrett D'Amore 		stfp->stf_count--;
509*49ef7e06SGarrett D'Amore 
510*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_destroy(sp, stpp);
511*49ef7e06SGarrett D'Amore 
512*49ef7e06SGarrett D'Amore 		stpp = next;
513*49ef7e06SGarrett D'Amore 	}
514*49ef7e06SGarrett D'Amore 	ASSERT3U(stfp->stf_count, ==, 0);
515*49ef7e06SGarrett D'Amore 
516*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
517*49ef7e06SGarrett D'Amore }
518*49ef7e06SGarrett D'Amore 
519*49ef7e06SGarrett D'Amore static inline void
sfxge_tx_qfbp_put(sfxge_txq_t * stp,sfxge_tx_buffer_t * stbp)520*49ef7e06SGarrett D'Amore sfxge_tx_qfbp_put(sfxge_txq_t *stp, sfxge_tx_buffer_t *stbp)
521*49ef7e06SGarrett D'Amore {
522*49ef7e06SGarrett D'Amore 	sfxge_tx_fbp_t *stfp = &(stp->st_fbp);
523*49ef7e06SGarrett D'Amore 
524*49ef7e06SGarrett D'Amore 	ASSERT3P(stbp->stb_next, ==, NULL);
525*49ef7e06SGarrett D'Amore 	ASSERT3U(stbp->stb_off, ==, 0);
526*49ef7e06SGarrett D'Amore 	ASSERT3U(stbp->stb_esm.esm_used, ==, 0);
527*49ef7e06SGarrett D'Amore 
528*49ef7e06SGarrett D'Amore 	stbp->stb_next = stfp->stf_stbp;
529*49ef7e06SGarrett D'Amore 	stfp->stf_stbp = stbp;
530*49ef7e06SGarrett D'Amore 	stfp->stf_count++;
531*49ef7e06SGarrett D'Amore }
532*49ef7e06SGarrett D'Amore 
533*49ef7e06SGarrett D'Amore 
534*49ef7e06SGarrett D'Amore static inline sfxge_tx_buffer_t *
sfxge_tx_qfbp_get(sfxge_txq_t * stp)535*49ef7e06SGarrett D'Amore sfxge_tx_qfbp_get(sfxge_txq_t *stp)
536*49ef7e06SGarrett D'Amore {
537*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp;
538*49ef7e06SGarrett D'Amore 	sfxge_tx_fbp_t *stfp = &(stp->st_fbp);
539*49ef7e06SGarrett D'Amore 
540*49ef7e06SGarrett D'Amore 	stbp = stfp->stf_stbp;
541*49ef7e06SGarrett D'Amore 	if (stbp == NULL) {
542*49ef7e06SGarrett D'Amore 		ASSERT3U(stfp->stf_count, ==, 0);
543*49ef7e06SGarrett D'Amore 		return (NULL);
544*49ef7e06SGarrett D'Amore 	}
545*49ef7e06SGarrett D'Amore 
546*49ef7e06SGarrett D'Amore 	stfp->stf_stbp = stbp->stb_next;
547*49ef7e06SGarrett D'Amore 	stbp->stb_next = NULL;
548*49ef7e06SGarrett D'Amore 
549*49ef7e06SGarrett D'Amore 	ASSERT3U(stfp->stf_count, >, 0);
550*49ef7e06SGarrett D'Amore 	stfp->stf_count--;
551*49ef7e06SGarrett D'Amore 
552*49ef7e06SGarrett D'Amore 	if (stfp->stf_count != 0) {
553*49ef7e06SGarrett D'Amore 		ASSERT(stfp->stf_stbp != NULL);
554*49ef7e06SGarrett D'Amore 		prefetch_read_many(stfp->stf_stbp);
555*49ef7e06SGarrett D'Amore 	}
556*49ef7e06SGarrett D'Amore 
557*49ef7e06SGarrett D'Amore 	return (stbp);
558*49ef7e06SGarrett D'Amore }
559*49ef7e06SGarrett D'Amore 
560*49ef7e06SGarrett D'Amore static void
sfxge_tx_qfbp_empty(sfxge_txq_t * stp)561*49ef7e06SGarrett D'Amore sfxge_tx_qfbp_empty(sfxge_txq_t *stp)
562*49ef7e06SGarrett D'Amore {
563*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
564*49ef7e06SGarrett D'Amore 	sfxge_tx_fbp_t *stfp = &(stp->st_fbp);
565*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp;
566*49ef7e06SGarrett D'Amore 
567*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
568*49ef7e06SGarrett D'Amore 
569*49ef7e06SGarrett D'Amore 	stbp = stfp->stf_stbp;
570*49ef7e06SGarrett D'Amore 	stfp->stf_stbp = NULL;
571*49ef7e06SGarrett D'Amore 
572*49ef7e06SGarrett D'Amore 	while (stbp != NULL) {
573*49ef7e06SGarrett D'Amore 		sfxge_tx_buffer_t *next;
574*49ef7e06SGarrett D'Amore 
575*49ef7e06SGarrett D'Amore 		next = stbp->stb_next;
576*49ef7e06SGarrett D'Amore 		stbp->stb_next = NULL;
577*49ef7e06SGarrett D'Amore 
578*49ef7e06SGarrett D'Amore 		ASSERT3U(stfp->stf_count, >, 0);
579*49ef7e06SGarrett D'Amore 		stfp->stf_count--;
580*49ef7e06SGarrett D'Amore 
581*49ef7e06SGarrett D'Amore 		kmem_cache_free(sp->s_tbc, stbp);
582*49ef7e06SGarrett D'Amore 
583*49ef7e06SGarrett D'Amore 		stbp = next;
584*49ef7e06SGarrett D'Amore 	}
585*49ef7e06SGarrett D'Amore 	ASSERT3U(stfp->stf_count, ==, 0);
586*49ef7e06SGarrett D'Amore 
587*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
588*49ef7e06SGarrett D'Amore }
589*49ef7e06SGarrett D'Amore 
590*49ef7e06SGarrett D'Amore static inline void
sfxge_tx_qfmp_put(sfxge_txq_t * stp,sfxge_tx_mapping_t * stmp)591*49ef7e06SGarrett D'Amore sfxge_tx_qfmp_put(sfxge_txq_t *stp, sfxge_tx_mapping_t *stmp)
592*49ef7e06SGarrett D'Amore {
593*49ef7e06SGarrett D'Amore 	sfxge_tx_fmp_t *stfp = &(stp->st_fmp);
594*49ef7e06SGarrett D'Amore 
595*49ef7e06SGarrett D'Amore 	ASSERT3P(stmp->stm_next, ==, NULL);
596*49ef7e06SGarrett D'Amore 	ASSERT3P(stmp->stm_mp, ==, NULL);
597*49ef7e06SGarrett D'Amore 	ASSERT3P(stmp->stm_base, ==, NULL);
598*49ef7e06SGarrett D'Amore 	ASSERT3U(stmp->stm_off, ==, 0);
599*49ef7e06SGarrett D'Amore 	ASSERT3U(stmp->stm_size, ==, 0);
600*49ef7e06SGarrett D'Amore 
601*49ef7e06SGarrett D'Amore 	stmp->stm_next = stfp->stf_stmp;
602*49ef7e06SGarrett D'Amore 	stfp->stf_stmp = stmp;
603*49ef7e06SGarrett D'Amore 	stfp->stf_count++;
604*49ef7e06SGarrett D'Amore }
605*49ef7e06SGarrett D'Amore 
606*49ef7e06SGarrett D'Amore static inline sfxge_tx_mapping_t *
sfxge_tx_qfmp_get(sfxge_txq_t * stp)607*49ef7e06SGarrett D'Amore sfxge_tx_qfmp_get(sfxge_txq_t *stp)
608*49ef7e06SGarrett D'Amore {
609*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp;
610*49ef7e06SGarrett D'Amore 	sfxge_tx_fmp_t *stfp = &(stp->st_fmp);
611*49ef7e06SGarrett D'Amore 
612*49ef7e06SGarrett D'Amore 	stmp = stfp->stf_stmp;
613*49ef7e06SGarrett D'Amore 	if (stmp == NULL) {
614*49ef7e06SGarrett D'Amore 		ASSERT3U(stfp->stf_count, ==, 0);
615*49ef7e06SGarrett D'Amore 		return (NULL);
616*49ef7e06SGarrett D'Amore 	}
617*49ef7e06SGarrett D'Amore 
618*49ef7e06SGarrett D'Amore 	stfp->stf_stmp = stmp->stm_next;
619*49ef7e06SGarrett D'Amore 	stmp->stm_next = NULL;
620*49ef7e06SGarrett D'Amore 
621*49ef7e06SGarrett D'Amore 	ASSERT3U(stfp->stf_count, >, 0);
622*49ef7e06SGarrett D'Amore 	stfp->stf_count--;
623*49ef7e06SGarrett D'Amore 
624*49ef7e06SGarrett D'Amore 	if (stfp->stf_count != 0) {
625*49ef7e06SGarrett D'Amore 		ASSERT(stfp->stf_stmp != NULL);
626*49ef7e06SGarrett D'Amore 		prefetch_read_many(stfp->stf_stmp);
627*49ef7e06SGarrett D'Amore 	}
628*49ef7e06SGarrett D'Amore 	return (stmp);
629*49ef7e06SGarrett D'Amore }
630*49ef7e06SGarrett D'Amore 
631*49ef7e06SGarrett D'Amore static void
sfxge_tx_qfmp_empty(sfxge_txq_t * stp)632*49ef7e06SGarrett D'Amore sfxge_tx_qfmp_empty(sfxge_txq_t *stp)
633*49ef7e06SGarrett D'Amore {
634*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
635*49ef7e06SGarrett D'Amore 	sfxge_tx_fmp_t *stfp = &(stp->st_fmp);
636*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp;
637*49ef7e06SGarrett D'Amore 
638*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
639*49ef7e06SGarrett D'Amore 
640*49ef7e06SGarrett D'Amore 	stmp = stfp->stf_stmp;
641*49ef7e06SGarrett D'Amore 	stfp->stf_stmp = NULL;
642*49ef7e06SGarrett D'Amore 
643*49ef7e06SGarrett D'Amore 	while (stmp != NULL) {
644*49ef7e06SGarrett D'Amore 		sfxge_tx_mapping_t *next;
645*49ef7e06SGarrett D'Amore 
646*49ef7e06SGarrett D'Amore 		next = stmp->stm_next;
647*49ef7e06SGarrett D'Amore 		stmp->stm_next = NULL;
648*49ef7e06SGarrett D'Amore 
649*49ef7e06SGarrett D'Amore 		ASSERT3U(stfp->stf_count, >, 0);
650*49ef7e06SGarrett D'Amore 		stfp->stf_count--;
651*49ef7e06SGarrett D'Amore 
652*49ef7e06SGarrett D'Amore 		kmem_cache_free(sp->s_tmc, stmp);
653*49ef7e06SGarrett D'Amore 
654*49ef7e06SGarrett D'Amore 		stmp = next;
655*49ef7e06SGarrett D'Amore 	}
656*49ef7e06SGarrett D'Amore 	ASSERT3U(stfp->stf_count, ==, 0);
657*49ef7e06SGarrett D'Amore 
658*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
659*49ef7e06SGarrett D'Amore }
660*49ef7e06SGarrett D'Amore 
661*49ef7e06SGarrett D'Amore static void
sfxge_tx_msgb_unbind(sfxge_tx_mapping_t * stmp)662*49ef7e06SGarrett D'Amore sfxge_tx_msgb_unbind(sfxge_tx_mapping_t *stmp)
663*49ef7e06SGarrett D'Amore {
664*49ef7e06SGarrett D'Amore 	bzero(stmp->stm_addr, sizeof (uint64_t) * SFXGE_TX_MAPPING_NADDR);
665*49ef7e06SGarrett D'Amore 	stmp->stm_off = 0;
666*49ef7e06SGarrett D'Amore 
667*49ef7e06SGarrett D'Amore 	(void) ddi_dma_unbind_handle(stmp->stm_dma_handle);
668*49ef7e06SGarrett D'Amore 
669*49ef7e06SGarrett D'Amore 	stmp->stm_size = 0;
670*49ef7e06SGarrett D'Amore 	stmp->stm_base = NULL;
671*49ef7e06SGarrett D'Amore 
672*49ef7e06SGarrett D'Amore 	stmp->stm_mp = NULL;
673*49ef7e06SGarrett D'Amore }
674*49ef7e06SGarrett D'Amore 
675*49ef7e06SGarrett D'Amore #define	SFXGE_TX_DESCSHIFT	12
676*49ef7e06SGarrett D'Amore #define	SFXGE_TX_DESCSIZE	(1 << 12)
677*49ef7e06SGarrett D'Amore 
678*49ef7e06SGarrett D'Amore #define	SFXGE_TX_DESCOFFSET	(SFXGE_TX_DESCSIZE - 1)
679*49ef7e06SGarrett D'Amore #define	SFXGE_TX_DESCMASK	(~SFXGE_TX_DESCOFFSET)
680*49ef7e06SGarrett D'Amore 
681*49ef7e06SGarrett D'Amore static int
sfxge_tx_msgb_bind(mblk_t * mp,sfxge_tx_mapping_t * stmp)682*49ef7e06SGarrett D'Amore sfxge_tx_msgb_bind(mblk_t *mp, sfxge_tx_mapping_t *stmp)
683*49ef7e06SGarrett D'Amore {
684*49ef7e06SGarrett D'Amore 	ddi_dma_cookie_t dmac;
685*49ef7e06SGarrett D'Amore 	unsigned int ncookies;
686*49ef7e06SGarrett D'Amore 	size_t size;
687*49ef7e06SGarrett D'Amore 	unsigned int n;
688*49ef7e06SGarrett D'Amore 	int rc;
689*49ef7e06SGarrett D'Amore 
690*49ef7e06SGarrett D'Amore 	ASSERT(mp != NULL);
691*49ef7e06SGarrett D'Amore 	ASSERT3U(DB_TYPE(mp), ==, M_DATA);
692*49ef7e06SGarrett D'Amore 
693*49ef7e06SGarrett D'Amore 	ASSERT(stmp->stm_mp == NULL);
694*49ef7e06SGarrett D'Amore 	stmp->stm_mp = mp;
695*49ef7e06SGarrett D'Amore 
696*49ef7e06SGarrett D'Amore 	stmp->stm_base = (caddr_t)(mp->b_rptr);
697*49ef7e06SGarrett D'Amore 	stmp->stm_size = MBLKL(mp);
698*49ef7e06SGarrett D'Amore 
699*49ef7e06SGarrett D'Amore 	/* Bind the STREAMS block to the mapping */
700*49ef7e06SGarrett D'Amore 	rc = ddi_dma_addr_bind_handle(stmp->stm_dma_handle, NULL,
701*49ef7e06SGarrett D'Amore 	    stmp->stm_base, stmp->stm_size, DDI_DMA_WRITE | DDI_DMA_STREAMING,
702*49ef7e06SGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &dmac, &ncookies);
703*49ef7e06SGarrett D'Amore 	if (rc != DDI_DMA_MAPPED)
704*49ef7e06SGarrett D'Amore 		goto fail1;
705*49ef7e06SGarrett D'Amore 
706*49ef7e06SGarrett D'Amore 	ASSERT3U(ncookies, <=, SFXGE_TX_MAPPING_NADDR);
707*49ef7e06SGarrett D'Amore 
708*49ef7e06SGarrett D'Amore 	/*
709*49ef7e06SGarrett D'Amore 	 * Construct an array of addresses and an initial
710*49ef7e06SGarrett D'Amore 	 * offset.
711*49ef7e06SGarrett D'Amore 	 */
712*49ef7e06SGarrett D'Amore 	n = 0;
713*49ef7e06SGarrett D'Amore 	stmp->stm_addr[n++] = dmac.dmac_laddress & SFXGE_TX_DESCMASK;
714*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(addr, uint64_t, dmac.dmac_laddress & SFXGE_TX_DESCMASK);
715*49ef7e06SGarrett D'Amore 
716*49ef7e06SGarrett D'Amore 	stmp->stm_off = dmac.dmac_laddress & SFXGE_TX_DESCOFFSET;
717*49ef7e06SGarrett D'Amore 
718*49ef7e06SGarrett D'Amore 	size = MIN(SFXGE_TX_DESCSIZE - stmp->stm_off, dmac.dmac_size);
719*49ef7e06SGarrett D'Amore 	dmac.dmac_laddress += size;
720*49ef7e06SGarrett D'Amore 	dmac.dmac_size -= size;
721*49ef7e06SGarrett D'Amore 
722*49ef7e06SGarrett D'Amore 	for (;;) {
723*49ef7e06SGarrett D'Amore 		ASSERT3U(n, <, SFXGE_TX_MAPPING_NADDR);
724*49ef7e06SGarrett D'Amore 
725*49ef7e06SGarrett D'Amore 		if (dmac.dmac_size == 0) {
726*49ef7e06SGarrett D'Amore 			if (--ncookies == 0)
727*49ef7e06SGarrett D'Amore 				break;
728*49ef7e06SGarrett D'Amore 
729*49ef7e06SGarrett D'Amore 			ddi_dma_nextcookie(stmp->stm_dma_handle, &dmac);
730*49ef7e06SGarrett D'Amore 		}
731*49ef7e06SGarrett D'Amore 
732*49ef7e06SGarrett D'Amore 		ASSERT((dmac.dmac_laddress & SFXGE_TX_DESCMASK) != 0);
733*49ef7e06SGarrett D'Amore 		ASSERT((dmac.dmac_laddress & SFXGE_TX_DESCOFFSET) == 0);
734*49ef7e06SGarrett D'Amore 		stmp->stm_addr[n++] = dmac.dmac_laddress;
735*49ef7e06SGarrett D'Amore 		DTRACE_PROBE1(addr, uint64_t, dmac.dmac_laddress);
736*49ef7e06SGarrett D'Amore 
737*49ef7e06SGarrett D'Amore 		size = MIN(SFXGE_TX_DESCSIZE, dmac.dmac_size);
738*49ef7e06SGarrett D'Amore 		dmac.dmac_laddress += size;
739*49ef7e06SGarrett D'Amore 		dmac.dmac_size -= size;
740*49ef7e06SGarrett D'Amore 	}
741*49ef7e06SGarrett D'Amore 	ASSERT3U(n, <=, SFXGE_TX_MAPPING_NADDR);
742*49ef7e06SGarrett D'Amore 
743*49ef7e06SGarrett D'Amore 	return (0);
744*49ef7e06SGarrett D'Amore 
745*49ef7e06SGarrett D'Amore fail1:
746*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
747*49ef7e06SGarrett D'Amore 
748*49ef7e06SGarrett D'Amore 	stmp->stm_size = 0;
749*49ef7e06SGarrett D'Amore 	stmp->stm_base = NULL;
750*49ef7e06SGarrett D'Amore 
751*49ef7e06SGarrett D'Amore 	stmp->stm_mp = NULL;
752*49ef7e06SGarrett D'Amore 
753*49ef7e06SGarrett D'Amore 	return (-1);
754*49ef7e06SGarrett D'Amore }
755*49ef7e06SGarrett D'Amore 
756*49ef7e06SGarrett D'Amore static void
sfxge_tx_qreap(sfxge_txq_t * stp)757*49ef7e06SGarrett D'Amore sfxge_tx_qreap(sfxge_txq_t *stp)
758*49ef7e06SGarrett D'Amore {
759*49ef7e06SGarrett D'Amore 	unsigned int reaped;
760*49ef7e06SGarrett D'Amore 
761*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
762*49ef7e06SGarrett D'Amore 
763*49ef7e06SGarrett D'Amore 	reaped = stp->st_reaped;
764*49ef7e06SGarrett D'Amore 	while (reaped != stp->st_completed) {
765*49ef7e06SGarrett D'Amore 		unsigned int id;
766*49ef7e06SGarrett D'Amore 		sfxge_tx_mapping_t *stmp;
767*49ef7e06SGarrett D'Amore 		sfxge_tx_buffer_t *stbp;
768*49ef7e06SGarrett D'Amore 
769*49ef7e06SGarrett D'Amore 		id = reaped++ & (SFXGE_TX_NDESCS - 1);
770*49ef7e06SGarrett D'Amore 
771*49ef7e06SGarrett D'Amore 		ASSERT3P(stp->st_mp[id], ==, NULL);
772*49ef7e06SGarrett D'Amore 
773*49ef7e06SGarrett D'Amore 		if ((stmp = stp->st_stmp[id]) != NULL) {
774*49ef7e06SGarrett D'Amore 			stp->st_stmp[id] = NULL;
775*49ef7e06SGarrett D'Amore 
776*49ef7e06SGarrett D'Amore 			/* Free all the mappings */
777*49ef7e06SGarrett D'Amore 			do {
778*49ef7e06SGarrett D'Amore 				sfxge_tx_mapping_t *next;
779*49ef7e06SGarrett D'Amore 
780*49ef7e06SGarrett D'Amore 				next = stmp->stm_next;
781*49ef7e06SGarrett D'Amore 				stmp->stm_next = NULL;
782*49ef7e06SGarrett D'Amore 
783*49ef7e06SGarrett D'Amore 				sfxge_tx_qfmp_put(stp, stmp);
784*49ef7e06SGarrett D'Amore 
785*49ef7e06SGarrett D'Amore 				stmp = next;
786*49ef7e06SGarrett D'Amore 			} while (stmp != NULL);
787*49ef7e06SGarrett D'Amore 		}
788*49ef7e06SGarrett D'Amore 
789*49ef7e06SGarrett D'Amore 		if ((stbp = stp->st_stbp[id]) != NULL) {
790*49ef7e06SGarrett D'Amore 			stp->st_stbp[id] = NULL;
791*49ef7e06SGarrett D'Amore 
792*49ef7e06SGarrett D'Amore 			/* Free all the buffers */
793*49ef7e06SGarrett D'Amore 			do {
794*49ef7e06SGarrett D'Amore 				sfxge_tx_buffer_t *next;
795*49ef7e06SGarrett D'Amore 
796*49ef7e06SGarrett D'Amore 				next = stbp->stb_next;
797*49ef7e06SGarrett D'Amore 				stbp->stb_next = NULL;
798*49ef7e06SGarrett D'Amore 
799*49ef7e06SGarrett D'Amore 				stbp->stb_esm.esm_used = 0;
800*49ef7e06SGarrett D'Amore 				stbp->stb_off = 0;
801*49ef7e06SGarrett D'Amore 
802*49ef7e06SGarrett D'Amore 				sfxge_tx_qfbp_put(stp, stbp);
803*49ef7e06SGarrett D'Amore 
804*49ef7e06SGarrett D'Amore 				stbp = next;
805*49ef7e06SGarrett D'Amore 			} while (stbp != NULL);
806*49ef7e06SGarrett D'Amore 		}
807*49ef7e06SGarrett D'Amore 	}
808*49ef7e06SGarrett D'Amore 	stp->st_reaped = reaped;
809*49ef7e06SGarrett D'Amore }
810*49ef7e06SGarrett D'Amore 
811*49ef7e06SGarrett D'Amore static void
sfxge_tx_qlist_abort(sfxge_txq_t * stp)812*49ef7e06SGarrett D'Amore sfxge_tx_qlist_abort(sfxge_txq_t *stp)
813*49ef7e06SGarrett D'Amore {
814*49ef7e06SGarrett D'Amore 	unsigned int id;
815*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp;
816*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp;
817*49ef7e06SGarrett D'Amore 	mblk_t *mp;
818*49ef7e06SGarrett D'Amore 
819*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
820*49ef7e06SGarrett D'Amore 
821*49ef7e06SGarrett D'Amore 	id = stp->st_added & (SFXGE_TX_NDESCS - 1);
822*49ef7e06SGarrett D'Amore 
823*49ef7e06SGarrett D'Amore 	/* Clear the completion information */
824*49ef7e06SGarrett D'Amore 	stmp = stp->st_stmp[id];
825*49ef7e06SGarrett D'Amore 	stp->st_stmp[id] = NULL;
826*49ef7e06SGarrett D'Amore 
827*49ef7e06SGarrett D'Amore 	/* Free any mappings that were used */
828*49ef7e06SGarrett D'Amore 	while (stmp != NULL) {
829*49ef7e06SGarrett D'Amore 		sfxge_tx_mapping_t *next;
830*49ef7e06SGarrett D'Amore 
831*49ef7e06SGarrett D'Amore 		next = stmp->stm_next;
832*49ef7e06SGarrett D'Amore 		stmp->stm_next = NULL;
833*49ef7e06SGarrett D'Amore 
834*49ef7e06SGarrett D'Amore 		if (stmp->stm_mp != NULL)
835*49ef7e06SGarrett D'Amore 			sfxge_tx_msgb_unbind(stmp);
836*49ef7e06SGarrett D'Amore 
837*49ef7e06SGarrett D'Amore 		sfxge_tx_qfmp_put(stp, stmp);
838*49ef7e06SGarrett D'Amore 
839*49ef7e06SGarrett D'Amore 		stmp = next;
840*49ef7e06SGarrett D'Amore 	}
841*49ef7e06SGarrett D'Amore 
842*49ef7e06SGarrett D'Amore 	stbp = stp->st_stbp[id];
843*49ef7e06SGarrett D'Amore 	stp->st_stbp[id] = NULL;
844*49ef7e06SGarrett D'Amore 
845*49ef7e06SGarrett D'Amore 	/* Free any buffers that were used */
846*49ef7e06SGarrett D'Amore 	while (stbp != NULL) {
847*49ef7e06SGarrett D'Amore 		sfxge_tx_buffer_t *next;
848*49ef7e06SGarrett D'Amore 
849*49ef7e06SGarrett D'Amore 		next = stbp->stb_next;
850*49ef7e06SGarrett D'Amore 		stbp->stb_next = NULL;
851*49ef7e06SGarrett D'Amore 
852*49ef7e06SGarrett D'Amore 		stbp->stb_off = 0;
853*49ef7e06SGarrett D'Amore 		stbp->stb_esm.esm_used = 0;
854*49ef7e06SGarrett D'Amore 
855*49ef7e06SGarrett D'Amore 		sfxge_tx_qfbp_put(stp, stbp);
856*49ef7e06SGarrett D'Amore 
857*49ef7e06SGarrett D'Amore 		stbp = next;
858*49ef7e06SGarrett D'Amore 	}
859*49ef7e06SGarrett D'Amore 
860*49ef7e06SGarrett D'Amore 	mp = stp->st_mp[id];
861*49ef7e06SGarrett D'Amore 	stp->st_mp[id] = NULL;
862*49ef7e06SGarrett D'Amore 
863*49ef7e06SGarrett D'Amore 	if (mp != NULL)
864*49ef7e06SGarrett D'Amore 		freemsg(mp);
865*49ef7e06SGarrett D'Amore 
866*49ef7e06SGarrett D'Amore 	/* Clear the fragment list */
867*49ef7e06SGarrett D'Amore 	stp->st_n = 0;
868*49ef7e06SGarrett D'Amore }
869*49ef7e06SGarrett D'Amore 
870*49ef7e06SGarrett D'Amore /* Push descriptors to the TX ring setting blocked if no space */
871*49ef7e06SGarrett D'Amore static void
sfxge_tx_qlist_post(sfxge_txq_t * stp)872*49ef7e06SGarrett D'Amore sfxge_tx_qlist_post(sfxge_txq_t *stp)
873*49ef7e06SGarrett D'Amore {
874*49ef7e06SGarrett D'Amore 	unsigned int id;
875*49ef7e06SGarrett D'Amore 	unsigned int level;
876*49ef7e06SGarrett D'Amore 	unsigned int available;
877*49ef7e06SGarrett D'Amore 	int rc;
878*49ef7e06SGarrett D'Amore 
879*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
880*49ef7e06SGarrett D'Amore 
881*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_n != 0);
882*49ef7e06SGarrett D'Amore 
883*49ef7e06SGarrett D'Amore again:
884*49ef7e06SGarrett D'Amore 	level = stp->st_added - stp->st_reaped;
885*49ef7e06SGarrett D'Amore 	available = EFX_TXQ_LIMIT(SFXGE_TX_NDESCS) - level;
886*49ef7e06SGarrett D'Amore 
887*49ef7e06SGarrett D'Amore 	id = stp->st_added & (SFXGE_TX_NDESCS - 1);
888*49ef7e06SGarrett D'Amore 
889*49ef7e06SGarrett D'Amore 	if (available < stp->st_n) {
890*49ef7e06SGarrett D'Amore 		rc = ENOSPC;
891*49ef7e06SGarrett D'Amore 		goto fail1;
892*49ef7e06SGarrett D'Amore 	}
893*49ef7e06SGarrett D'Amore 
894*49ef7e06SGarrett D'Amore 	ASSERT3U(available, >=, stp->st_n);
895*49ef7e06SGarrett D'Amore 
896*49ef7e06SGarrett D'Amore 	/* Post the fragment list */
897*49ef7e06SGarrett D'Amore 	if ((rc = efx_tx_qpost(stp->st_etp, stp->st_eb, stp->st_n,
898*49ef7e06SGarrett D'Amore 	    stp->st_reaped, &(stp->st_added))) != 0)
899*49ef7e06SGarrett D'Amore 		goto fail2;
900*49ef7e06SGarrett D'Amore 
901*49ef7e06SGarrett D'Amore 	/*
902*49ef7e06SGarrett D'Amore 	 * If the list took more than a single descriptor then we need to
903*49ef7e06SGarrett D'Amore 	 * to move the completion information so it is referenced by the last
904*49ef7e06SGarrett D'Amore 	 * descriptor.
905*49ef7e06SGarrett D'Amore 	 */
906*49ef7e06SGarrett D'Amore 	if (((stp->st_added - 1) & (SFXGE_TX_NDESCS - 1)) != id) {
907*49ef7e06SGarrett D'Amore 		sfxge_tx_mapping_t *stmp;
908*49ef7e06SGarrett D'Amore 		sfxge_tx_buffer_t *stbp;
909*49ef7e06SGarrett D'Amore 		mblk_t *mp;
910*49ef7e06SGarrett D'Amore 
911*49ef7e06SGarrett D'Amore 		stmp = stp->st_stmp[id];
912*49ef7e06SGarrett D'Amore 		stp->st_stmp[id] = NULL;
913*49ef7e06SGarrett D'Amore 
914*49ef7e06SGarrett D'Amore 		stbp = stp->st_stbp[id];
915*49ef7e06SGarrett D'Amore 		stp->st_stbp[id] = NULL;
916*49ef7e06SGarrett D'Amore 
917*49ef7e06SGarrett D'Amore 		mp = stp->st_mp[id];
918*49ef7e06SGarrett D'Amore 		stp->st_mp[id] = NULL;
919*49ef7e06SGarrett D'Amore 
920*49ef7e06SGarrett D'Amore 		id = (stp->st_added - 1) & (SFXGE_TX_NDESCS - 1);
921*49ef7e06SGarrett D'Amore 
922*49ef7e06SGarrett D'Amore 		ASSERT(stp->st_stmp[id] == NULL);
923*49ef7e06SGarrett D'Amore 		stp->st_stmp[id] = stmp;
924*49ef7e06SGarrett D'Amore 
925*49ef7e06SGarrett D'Amore 		ASSERT(stp->st_stbp[id] == NULL);
926*49ef7e06SGarrett D'Amore 		stp->st_stbp[id] = stbp;
927*49ef7e06SGarrett D'Amore 
928*49ef7e06SGarrett D'Amore 		ASSERT(stp->st_mp[id] == NULL);
929*49ef7e06SGarrett D'Amore 		stp->st_mp[id] = mp;
930*49ef7e06SGarrett D'Amore 	}
931*49ef7e06SGarrett D'Amore 
932*49ef7e06SGarrett D'Amore 	/* Clear the list */
933*49ef7e06SGarrett D'Amore 	stp->st_n = 0;
934*49ef7e06SGarrett D'Amore 
935*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_unblock, ==, SFXGE_TXQ_NOT_BLOCKED);
936*49ef7e06SGarrett D'Amore 	return;
937*49ef7e06SGarrett D'Amore 
938*49ef7e06SGarrett D'Amore fail2:
939*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
940*49ef7e06SGarrett D'Amore fail1:
941*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
942*49ef7e06SGarrett D'Amore 
943*49ef7e06SGarrett D'Amore 	ASSERT(rc == ENOSPC);
944*49ef7e06SGarrett D'Amore 
945*49ef7e06SGarrett D'Amore 	level = stp->st_added - stp->st_completed;
946*49ef7e06SGarrett D'Amore 	available = EFX_TXQ_LIMIT(SFXGE_TX_NDESCS) - level;
947*49ef7e06SGarrett D'Amore 
948*49ef7e06SGarrett D'Amore 	/*
949*49ef7e06SGarrett D'Amore 	 * If there would be enough space after we've reaped any completed
950*49ef7e06SGarrett D'Amore 	 * mappings and buffers, and we gain sufficient queue space by doing
951*49ef7e06SGarrett D'Amore 	 * so, then reap now and try posting again.
952*49ef7e06SGarrett D'Amore 	 */
953*49ef7e06SGarrett D'Amore 	if (stp->st_n <= available &&
954*49ef7e06SGarrett D'Amore 	    stp->st_completed - stp->st_reaped >= SFXGE_TX_BATCH) {
955*49ef7e06SGarrett D'Amore 		sfxge_tx_qreap(stp);
956*49ef7e06SGarrett D'Amore 
957*49ef7e06SGarrett D'Amore 		goto again;
958*49ef7e06SGarrett D'Amore 	}
959*49ef7e06SGarrett D'Amore 
960*49ef7e06SGarrett D'Amore 	/* Set the unblock level */
961*49ef7e06SGarrett D'Amore 	if (stp->st_unblock == SFXGE_TXQ_NOT_BLOCKED) {
962*49ef7e06SGarrett D'Amore 		stp->st_unblock = SFXGE_TXQ_UNBLOCK_LEVEL1;
963*49ef7e06SGarrett D'Amore 	} else {
964*49ef7e06SGarrett D'Amore 		ASSERT(stp->st_unblock == SFXGE_TXQ_UNBLOCK_LEVEL1);
965*49ef7e06SGarrett D'Amore 
966*49ef7e06SGarrett D'Amore 		stp->st_unblock = SFXGE_TXQ_UNBLOCK_LEVEL2;
967*49ef7e06SGarrett D'Amore 	}
968*49ef7e06SGarrett D'Amore 
969*49ef7e06SGarrett D'Amore 	/*
970*49ef7e06SGarrett D'Amore 	 * Avoid a race with completion interrupt handling that could leave the
971*49ef7e06SGarrett D'Amore 	 * queue blocked.
972*49ef7e06SGarrett D'Amore 	 *
973*49ef7e06SGarrett D'Amore 	 * NOTE: The use of st_pending rather than st_completed is intentional
974*49ef7e06SGarrett D'Amore 	 *	 as st_pending is updated per-event rather than per-batch and
975*49ef7e06SGarrett D'Amore 	 *	 therefore avoids needless deferring.
976*49ef7e06SGarrett D'Amore 	 */
977*49ef7e06SGarrett D'Amore 	if (stp->st_pending == stp->st_added) {
978*49ef7e06SGarrett D'Amore 		sfxge_tx_qreap(stp);
979*49ef7e06SGarrett D'Amore 
980*49ef7e06SGarrett D'Amore 		stp->st_unblock = SFXGE_TXQ_NOT_BLOCKED;
981*49ef7e06SGarrett D'Amore 		goto again;
982*49ef7e06SGarrett D'Amore 	}
983*49ef7e06SGarrett D'Amore 
984*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_unblock != SFXGE_TXQ_NOT_BLOCKED);
985*49ef7e06SGarrett D'Amore }
986*49ef7e06SGarrett D'Amore 
987*49ef7e06SGarrett D'Amore static int
sfxge_tx_kstat_update(kstat_t * ksp,int rw)988*49ef7e06SGarrett D'Amore sfxge_tx_kstat_update(kstat_t *ksp, int rw)
989*49ef7e06SGarrett D'Amore {
990*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = ksp->ks_private;
991*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
992*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
993*49ef7e06SGarrett D'Amore 	int rc;
994*49ef7e06SGarrett D'Amore 
995*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
996*49ef7e06SGarrett D'Amore 
997*49ef7e06SGarrett D'Amore 	if (rw != KSTAT_READ) {
998*49ef7e06SGarrett D'Amore 		rc = EACCES;
999*49ef7e06SGarrett D'Amore 		goto fail1;
1000*49ef7e06SGarrett D'Amore 	}
1001*49ef7e06SGarrett D'Amore 
1002*49ef7e06SGarrett D'Amore 	if (stp->st_state != SFXGE_TXQ_STARTED)
1003*49ef7e06SGarrett D'Amore 		goto done;
1004*49ef7e06SGarrett D'Amore 
1005*49ef7e06SGarrett D'Amore 	efx_tx_qstats_update(stp->st_etp, stp->st_stat);
1006*49ef7e06SGarrett D'Amore 	knp = (kstat_named_t *)ksp->ks_data + TX_NQSTATS;
1007*49ef7e06SGarrett D'Amore 	knp->value.ui64 = stdp->get_pkt_limit;
1008*49ef7e06SGarrett D'Amore 	knp++;
1009*49ef7e06SGarrett D'Amore 	knp->value.ui64 = stdp->put_pkt_limit;
1010*49ef7e06SGarrett D'Amore 	knp++;
1011*49ef7e06SGarrett D'Amore 	knp->value.ui64 = stdp->get_full_count;
1012*49ef7e06SGarrett D'Amore 	knp++;
1013*49ef7e06SGarrett D'Amore 	knp->value.ui64 = stdp->put_full_count;
1014*49ef7e06SGarrett D'Amore 
1015*49ef7e06SGarrett D'Amore done:
1016*49ef7e06SGarrett D'Amore 	return (0);
1017*49ef7e06SGarrett D'Amore 
1018*49ef7e06SGarrett D'Amore fail1:
1019*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1020*49ef7e06SGarrett D'Amore 
1021*49ef7e06SGarrett D'Amore 	return (rc);
1022*49ef7e06SGarrett D'Amore }
1023*49ef7e06SGarrett D'Amore 
1024*49ef7e06SGarrett D'Amore static int
sfxge_tx_kstat_init(sfxge_txq_t * stp)1025*49ef7e06SGarrett D'Amore sfxge_tx_kstat_init(sfxge_txq_t *stp)
1026*49ef7e06SGarrett D'Amore {
1027*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
1028*49ef7e06SGarrett D'Amore 	unsigned int index = stp->st_index;
1029*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
1030*49ef7e06SGarrett D'Amore 	kstat_t *ksp;
1031*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
1032*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
1033*49ef7e06SGarrett D'Amore 	unsigned int id;
1034*49ef7e06SGarrett D'Amore 	int rc;
1035*49ef7e06SGarrett D'Amore 
1036*49ef7e06SGarrett D'Amore 	/* Create the set */
1037*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s_txq%04d",
1038*49ef7e06SGarrett D'Amore 	    ddi_driver_name(dip), index);
1039*49ef7e06SGarrett D'Amore 
1040*49ef7e06SGarrett D'Amore 	if ((ksp = kstat_create((char *)ddi_driver_name(dip),
1041*49ef7e06SGarrett D'Amore 	    ddi_get_instance(dip), name, "queue", KSTAT_TYPE_NAMED,
1042*49ef7e06SGarrett D'Amore 	    TX_NQSTATS + 4, 0)) == NULL) {
1043*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
1044*49ef7e06SGarrett D'Amore 		goto fail1;
1045*49ef7e06SGarrett D'Amore 	}
1046*49ef7e06SGarrett D'Amore 
1047*49ef7e06SGarrett D'Amore 	stp->st_ksp = ksp;
1048*49ef7e06SGarrett D'Amore 
1049*49ef7e06SGarrett D'Amore 	ksp->ks_update = sfxge_tx_kstat_update;
1050*49ef7e06SGarrett D'Amore 	ksp->ks_private = stp;
1051*49ef7e06SGarrett D'Amore 	ksp->ks_lock = &(stp->st_lock);
1052*49ef7e06SGarrett D'Amore 
1053*49ef7e06SGarrett D'Amore 	/* Initialise the named stats */
1054*49ef7e06SGarrett D'Amore 	stp->st_stat = knp = ksp->ks_data;
1055*49ef7e06SGarrett D'Amore 	for (id = 0; id < TX_NQSTATS; id++) {
1056*49ef7e06SGarrett D'Amore 		kstat_named_init(knp, (char *)efx_tx_qstat_name(sp->s_enp, id),
1057*49ef7e06SGarrett D'Amore 		    KSTAT_DATA_UINT64);
1058*49ef7e06SGarrett D'Amore 		knp++;
1059*49ef7e06SGarrett D'Amore 	}
1060*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dpl_get_pkt_limit", KSTAT_DATA_UINT64);
1061*49ef7e06SGarrett D'Amore 	knp++;
1062*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dpl_put_pkt_limit", KSTAT_DATA_UINT64);
1063*49ef7e06SGarrett D'Amore 	knp++;
1064*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dpl_get_full_count", KSTAT_DATA_UINT64);
1065*49ef7e06SGarrett D'Amore 	knp++;
1066*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dpl_put_full_count", KSTAT_DATA_UINT64);
1067*49ef7e06SGarrett D'Amore 
1068*49ef7e06SGarrett D'Amore 	kstat_install(ksp);
1069*49ef7e06SGarrett D'Amore 	return (0);
1070*49ef7e06SGarrett D'Amore 
1071*49ef7e06SGarrett D'Amore fail1:
1072*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1073*49ef7e06SGarrett D'Amore 
1074*49ef7e06SGarrett D'Amore 	return (rc);
1075*49ef7e06SGarrett D'Amore }
1076*49ef7e06SGarrett D'Amore 
1077*49ef7e06SGarrett D'Amore static void
sfxge_tx_kstat_fini(sfxge_txq_t * stp)1078*49ef7e06SGarrett D'Amore sfxge_tx_kstat_fini(sfxge_txq_t *stp)
1079*49ef7e06SGarrett D'Amore {
1080*49ef7e06SGarrett D'Amore 	/* Destroy the set */
1081*49ef7e06SGarrett D'Amore 	kstat_delete(stp->st_ksp);
1082*49ef7e06SGarrett D'Amore 	stp->st_ksp = NULL;
1083*49ef7e06SGarrett D'Amore 	stp->st_stat = NULL;
1084*49ef7e06SGarrett D'Amore }
1085*49ef7e06SGarrett D'Amore 
1086*49ef7e06SGarrett D'Amore static int
sfxge_tx_qinit(sfxge_t * sp,unsigned int index,sfxge_txq_type_t type,unsigned int evq)1087*49ef7e06SGarrett D'Amore sfxge_tx_qinit(sfxge_t *sp, unsigned int index, sfxge_txq_type_t type,
1088*49ef7e06SGarrett D'Amore     unsigned int evq)
1089*49ef7e06SGarrett D'Amore {
1090*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp;
1091*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp;
1092*49ef7e06SGarrett D'Amore 	int rc;
1093*49ef7e06SGarrett D'Amore 
1094*49ef7e06SGarrett D'Amore 	ASSERT3U(index, <, EFX_ARRAY_SIZE(sp->s_stp));
1095*49ef7e06SGarrett D'Amore 	ASSERT3U(type, <, SFXGE_TXQ_NTYPES);
1096*49ef7e06SGarrett D'Amore 	ASSERT3U(evq, <, EFX_ARRAY_SIZE(sp->s_sep));
1097*49ef7e06SGarrett D'Amore 
1098*49ef7e06SGarrett D'Amore 	if ((stp = kmem_cache_alloc(sp->s_tqc, KM_SLEEP)) == NULL) {
1099*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
1100*49ef7e06SGarrett D'Amore 		goto fail1;
1101*49ef7e06SGarrett D'Amore 	}
1102*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_state, ==, SFXGE_TXQ_UNINITIALIZED);
1103*49ef7e06SGarrett D'Amore 
1104*49ef7e06SGarrett D'Amore 	stdp = &(stp->st_dpl);
1105*49ef7e06SGarrett D'Amore 
1106*49ef7e06SGarrett D'Amore 	stp->st_index = index;
1107*49ef7e06SGarrett D'Amore 	stp->st_type = type;
1108*49ef7e06SGarrett D'Amore 	stp->st_evq = evq;
1109*49ef7e06SGarrett D'Amore 
1110*49ef7e06SGarrett D'Amore 	mutex_init(&(stp->st_lock), NULL, MUTEX_DRIVER,
1111*49ef7e06SGarrett D'Amore 	    DDI_INTR_PRI(sp->s_intr.si_intr_pri));
1112*49ef7e06SGarrett D'Amore 
1113*49ef7e06SGarrett D'Amore 	/* Initialize the statistics */
1114*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_tx_kstat_init(stp)) != 0)
1115*49ef7e06SGarrett D'Amore 		goto fail2;
1116*49ef7e06SGarrett D'Amore 
1117*49ef7e06SGarrett D'Amore 	stdp->get_pkt_limit = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
1118*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "tx_dpl_get_pkt_limit",
1119*49ef7e06SGarrett D'Amore 	    SFXGE_TX_DPL_GET_PKT_LIMIT_DEFAULT);
1120*49ef7e06SGarrett D'Amore 
1121*49ef7e06SGarrett D'Amore 	stdp->put_pkt_limit = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
1122*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "tx_dpl_put_pkt_limit",
1123*49ef7e06SGarrett D'Amore 	    SFXGE_TX_DPL_PUT_PKT_LIMIT_DEFAULT);
1124*49ef7e06SGarrett D'Amore 
1125*49ef7e06SGarrett D'Amore 	/* Allocate a per-EVQ label for events from this TXQ */
1126*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_ev_txlabel_alloc(sp, evq, stp, &(stp->st_label))) != 0)
1127*49ef7e06SGarrett D'Amore 		goto fail2;
1128*49ef7e06SGarrett D'Amore 
1129*49ef7e06SGarrett D'Amore 	stp->st_state = SFXGE_TXQ_INITIALIZED;
1130*49ef7e06SGarrett D'Amore 
1131*49ef7e06SGarrett D'Amore 	/* Attach the TXQ to the driver */
1132*49ef7e06SGarrett D'Amore 	ASSERT3P(sp->s_stp[index], ==, NULL);
1133*49ef7e06SGarrett D'Amore 	sp->s_stp[index] = stp;
1134*49ef7e06SGarrett D'Amore 	sp->s_tx_qcount++;
1135*49ef7e06SGarrett D'Amore 
1136*49ef7e06SGarrett D'Amore 	return (0);
1137*49ef7e06SGarrett D'Amore 
1138*49ef7e06SGarrett D'Amore fail2:
1139*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1140*49ef7e06SGarrett D'Amore 
1141*49ef7e06SGarrett D'Amore 	sfxge_tx_kstat_fini(stp);
1142*49ef7e06SGarrett D'Amore 
1143*49ef7e06SGarrett D'Amore 
1144*49ef7e06SGarrett D'Amore 	stp->st_evq = 0;
1145*49ef7e06SGarrett D'Amore 	stp->st_type = 0;
1146*49ef7e06SGarrett D'Amore 	stp->st_index = 0;
1147*49ef7e06SGarrett D'Amore 
1148*49ef7e06SGarrett D'Amore 	mutex_destroy(&(stp->st_lock));
1149*49ef7e06SGarrett D'Amore 
1150*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_tqc, stp);
1151*49ef7e06SGarrett D'Amore 
1152*49ef7e06SGarrett D'Amore fail1:
1153*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1154*49ef7e06SGarrett D'Amore 
1155*49ef7e06SGarrett D'Amore 	return (rc);
1156*49ef7e06SGarrett D'Amore }
1157*49ef7e06SGarrett D'Amore 
1158*49ef7e06SGarrett D'Amore static int
sfxge_tx_qstart(sfxge_t * sp,unsigned int index)1159*49ef7e06SGarrett D'Amore sfxge_tx_qstart(sfxge_t *sp, unsigned int index)
1160*49ef7e06SGarrett D'Amore {
1161*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = sp->s_stp[index];
1162*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
1163*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp;
1164*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep;
1165*49ef7e06SGarrett D'Amore 	unsigned int evq;
1166*49ef7e06SGarrett D'Amore 	unsigned int flags;
1167*49ef7e06SGarrett D'Amore 	unsigned int desc_index;
1168*49ef7e06SGarrett D'Amore 	int rc;
1169*49ef7e06SGarrett D'Amore 
1170*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
1171*49ef7e06SGarrett D'Amore 
1172*49ef7e06SGarrett D'Amore 	esmp = &(stp->st_mem);
1173*49ef7e06SGarrett D'Amore 	evq = stp->st_evq;
1174*49ef7e06SGarrett D'Amore 	sep = sp->s_sep[evq];
1175*49ef7e06SGarrett D'Amore 
1176*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_state, ==, SFXGE_TXQ_INITIALIZED);
1177*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTED);
1178*49ef7e06SGarrett D'Amore 
1179*49ef7e06SGarrett D'Amore 	/* Zero the memory */
1180*49ef7e06SGarrett D'Amore 	bzero(esmp->esm_base, EFX_TXQ_SIZE(SFXGE_TX_NDESCS));
1181*49ef7e06SGarrett D'Amore 
1182*49ef7e06SGarrett D'Amore 	/* Program the buffer table */
1183*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_sram_buf_tbl_set(sp, stp->st_id, esmp,
1184*49ef7e06SGarrett D'Amore 	    EFX_TXQ_NBUFS(SFXGE_TX_NDESCS))) != 0)
1185*49ef7e06SGarrett D'Amore 		goto fail1;
1186*49ef7e06SGarrett D'Amore 
1187*49ef7e06SGarrett D'Amore 	switch (stp->st_type) {
1188*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_NON_CKSUM:
1189*49ef7e06SGarrett D'Amore 		flags = 0;
1190*49ef7e06SGarrett D'Amore 		break;
1191*49ef7e06SGarrett D'Amore 
1192*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_IP_CKSUM:
1193*49ef7e06SGarrett D'Amore 		flags = EFX_TXQ_CKSUM_IPV4;
1194*49ef7e06SGarrett D'Amore 		break;
1195*49ef7e06SGarrett D'Amore 
1196*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_IP_TCP_UDP_CKSUM:
1197*49ef7e06SGarrett D'Amore 		flags = EFX_TXQ_CKSUM_IPV4 | EFX_TXQ_CKSUM_TCPUDP;
1198*49ef7e06SGarrett D'Amore 		break;
1199*49ef7e06SGarrett D'Amore 
1200*49ef7e06SGarrett D'Amore 	default:
1201*49ef7e06SGarrett D'Amore 		ASSERT(B_FALSE);
1202*49ef7e06SGarrett D'Amore 
1203*49ef7e06SGarrett D'Amore 		flags = 0;
1204*49ef7e06SGarrett D'Amore 		break;
1205*49ef7e06SGarrett D'Amore 	}
1206*49ef7e06SGarrett D'Amore 
1207*49ef7e06SGarrett D'Amore 	/* Create the transmit queue */
1208*49ef7e06SGarrett D'Amore 	if ((rc = efx_tx_qcreate(enp, index, stp->st_label, esmp,
1209*49ef7e06SGarrett D'Amore 	    SFXGE_TX_NDESCS, stp->st_id, flags, sep->se_eep,
1210*49ef7e06SGarrett D'Amore 	    &(stp->st_etp), &desc_index)) != 0)
1211*49ef7e06SGarrett D'Amore 		goto fail2;
1212*49ef7e06SGarrett D'Amore 
1213*49ef7e06SGarrett D'Amore 	/* Initialise queue descriptor indexes */
1214*49ef7e06SGarrett D'Amore 	stp->st_added = desc_index;
1215*49ef7e06SGarrett D'Amore 	stp->st_pending = desc_index;
1216*49ef7e06SGarrett D'Amore 	stp->st_completed = desc_index;
1217*49ef7e06SGarrett D'Amore 	stp->st_reaped = desc_index;
1218*49ef7e06SGarrett D'Amore 
1219*49ef7e06SGarrett D'Amore 	/* Enable the transmit queue */
1220*49ef7e06SGarrett D'Amore 	efx_tx_qenable(stp->st_etp);
1221*49ef7e06SGarrett D'Amore 
1222*49ef7e06SGarrett D'Amore 	stp->st_state = SFXGE_TXQ_STARTED;
1223*49ef7e06SGarrett D'Amore 
1224*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
1225*49ef7e06SGarrett D'Amore 
1226*49ef7e06SGarrett D'Amore 	return (0);
1227*49ef7e06SGarrett D'Amore 
1228*49ef7e06SGarrett D'Amore fail2:
1229*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1230*49ef7e06SGarrett D'Amore 
1231*49ef7e06SGarrett D'Amore 	/* Clear entries from the buffer table */
1232*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_clear(sp, stp->st_id,
1233*49ef7e06SGarrett D'Amore 	    EFX_TXQ_NBUFS(SFXGE_TX_NDESCS));
1234*49ef7e06SGarrett D'Amore 
1235*49ef7e06SGarrett D'Amore fail1:
1236*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1237*49ef7e06SGarrett D'Amore 
1238*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
1239*49ef7e06SGarrett D'Amore 
1240*49ef7e06SGarrett D'Amore 	return (rc);
1241*49ef7e06SGarrett D'Amore }
1242*49ef7e06SGarrett D'Amore 
1243*49ef7e06SGarrett D'Amore static inline int
sfxge_tx_qmapping_add(sfxge_txq_t * stp,sfxge_tx_mapping_t * stmp,size_t * offp,size_t * limitp)1244*49ef7e06SGarrett D'Amore sfxge_tx_qmapping_add(sfxge_txq_t *stp, sfxge_tx_mapping_t *stmp,
1245*49ef7e06SGarrett D'Amore     size_t *offp, size_t *limitp)
1246*49ef7e06SGarrett D'Amore {
1247*49ef7e06SGarrett D'Amore 	mblk_t *mp;
1248*49ef7e06SGarrett D'Amore 	size_t mapping_off;
1249*49ef7e06SGarrett D'Amore 	size_t mapping_size;
1250*49ef7e06SGarrett D'Amore 	int rc;
1251*49ef7e06SGarrett D'Amore 
1252*49ef7e06SGarrett D'Amore 	ASSERT3U(*offp, <, stmp->stm_size);
1253*49ef7e06SGarrett D'Amore 	ASSERT(*limitp != 0);
1254*49ef7e06SGarrett D'Amore 
1255*49ef7e06SGarrett D'Amore 	mp = stmp->stm_mp;
1256*49ef7e06SGarrett D'Amore 
1257*49ef7e06SGarrett D'Amore 	ASSERT3P(stmp->stm_base, ==, mp->b_rptr);
1258*49ef7e06SGarrett D'Amore 	ASSERT3U(stmp->stm_size, ==, MBLKL(mp));
1259*49ef7e06SGarrett D'Amore 
1260*49ef7e06SGarrett D'Amore 	mapping_off = stmp->stm_off + *offp;
1261*49ef7e06SGarrett D'Amore 	mapping_size = stmp->stm_size - *offp;
1262*49ef7e06SGarrett D'Amore 
1263*49ef7e06SGarrett D'Amore 	while (mapping_size != 0 && *limitp != 0) {
1264*49ef7e06SGarrett D'Amore 		size_t page =
1265*49ef7e06SGarrett D'Amore 		    mapping_off >> SFXGE_TX_DESCSHIFT;
1266*49ef7e06SGarrett D'Amore 		size_t page_off =
1267*49ef7e06SGarrett D'Amore 		    mapping_off & SFXGE_TX_DESCOFFSET;
1268*49ef7e06SGarrett D'Amore 		size_t page_size =
1269*49ef7e06SGarrett D'Amore 		    SFXGE_TX_DESCSIZE - page_off;
1270*49ef7e06SGarrett D'Amore 		efx_buffer_t *ebp;
1271*49ef7e06SGarrett D'Amore 
1272*49ef7e06SGarrett D'Amore 		ASSERT3U(page, <, SFXGE_TX_MAPPING_NADDR);
1273*49ef7e06SGarrett D'Amore 		ASSERT((stmp->stm_addr[page] & SFXGE_TX_DESCMASK) != 0);
1274*49ef7e06SGarrett D'Amore 
1275*49ef7e06SGarrett D'Amore 		page_size = MIN(page_size, mapping_size);
1276*49ef7e06SGarrett D'Amore 		page_size = MIN(page_size, *limitp);
1277*49ef7e06SGarrett D'Amore 
1278*49ef7e06SGarrett D'Amore 		ASSERT3U(stp->st_n, <=,
1279*49ef7e06SGarrett D'Amore 		    EFX_TXQ_LIMIT(SFXGE_TX_NDESCS));
1280*49ef7e06SGarrett D'Amore 		if (stp->st_n ==
1281*49ef7e06SGarrett D'Amore 		    EFX_TXQ_LIMIT(SFXGE_TX_NDESCS)) {
1282*49ef7e06SGarrett D'Amore 			rc = ENOSPC;
1283*49ef7e06SGarrett D'Amore 			goto fail1;
1284*49ef7e06SGarrett D'Amore 		}
1285*49ef7e06SGarrett D'Amore 
1286*49ef7e06SGarrett D'Amore 		ebp = &(stp->st_eb[stp->st_n++]);
1287*49ef7e06SGarrett D'Amore 		ebp->eb_addr = stmp->stm_addr[page] +
1288*49ef7e06SGarrett D'Amore 		    page_off;
1289*49ef7e06SGarrett D'Amore 		ebp->eb_size = page_size;
1290*49ef7e06SGarrett D'Amore 
1291*49ef7e06SGarrett D'Amore 		*offp += page_size;
1292*49ef7e06SGarrett D'Amore 		*limitp -= page_size;
1293*49ef7e06SGarrett D'Amore 
1294*49ef7e06SGarrett D'Amore 		mapping_off += page_size;
1295*49ef7e06SGarrett D'Amore 		mapping_size -= page_size;
1296*49ef7e06SGarrett D'Amore 
1297*49ef7e06SGarrett D'Amore 		ebp->eb_eop = (*limitp == 0 ||
1298*49ef7e06SGarrett D'Amore 		    (mapping_size == 0 && mp->b_cont == NULL));
1299*49ef7e06SGarrett D'Amore 
1300*49ef7e06SGarrett D'Amore 		DTRACE_PROBE5(tx_mapping_add,
1301*49ef7e06SGarrett D'Amore 		    unsigned int, stp->st_index,
1302*49ef7e06SGarrett D'Amore 		    unsigned int, stp->st_n - 1,
1303*49ef7e06SGarrett D'Amore 		    uint64_t, ebp->eb_addr,
1304*49ef7e06SGarrett D'Amore 		    size_t, ebp->eb_size,
1305*49ef7e06SGarrett D'Amore 		    boolean_t, ebp->eb_eop);
1306*49ef7e06SGarrett D'Amore 	}
1307*49ef7e06SGarrett D'Amore 
1308*49ef7e06SGarrett D'Amore 	ASSERT3U(*offp, <=, stmp->stm_size);
1309*49ef7e06SGarrett D'Amore 
1310*49ef7e06SGarrett D'Amore 	return (0);
1311*49ef7e06SGarrett D'Amore 
1312*49ef7e06SGarrett D'Amore fail1:
1313*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1314*49ef7e06SGarrett D'Amore 
1315*49ef7e06SGarrett D'Amore 	return (rc);
1316*49ef7e06SGarrett D'Amore }
1317*49ef7e06SGarrett D'Amore 
1318*49ef7e06SGarrett D'Amore static inline int
sfxge_tx_qbuffer_add(sfxge_txq_t * stp,sfxge_tx_buffer_t * stbp,boolean_t eop)1319*49ef7e06SGarrett D'Amore sfxge_tx_qbuffer_add(sfxge_txq_t *stp, sfxge_tx_buffer_t *stbp, boolean_t eop)
1320*49ef7e06SGarrett D'Amore {
1321*49ef7e06SGarrett D'Amore 	efx_buffer_t *ebp;
1322*49ef7e06SGarrett D'Amore 	int rc;
1323*49ef7e06SGarrett D'Amore 
1324*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_n, <=,
1325*49ef7e06SGarrett D'Amore 	    EFX_TXQ_LIMIT(SFXGE_TX_NDESCS));
1326*49ef7e06SGarrett D'Amore 	if (stp->st_n == EFX_TXQ_LIMIT(SFXGE_TX_NDESCS)) {
1327*49ef7e06SGarrett D'Amore 		rc = ENOSPC;
1328*49ef7e06SGarrett D'Amore 		goto fail1;
1329*49ef7e06SGarrett D'Amore 	}
1330*49ef7e06SGarrett D'Amore 
1331*49ef7e06SGarrett D'Amore 	ebp = &(stp->st_eb[stp->st_n++]);
1332*49ef7e06SGarrett D'Amore 	ebp->eb_addr = stbp->stb_esm.esm_addr + stbp->stb_off;
1333*49ef7e06SGarrett D'Amore 	ebp->eb_size = stbp->stb_esm.esm_used - stbp->stb_off;
1334*49ef7e06SGarrett D'Amore 	ebp->eb_eop = eop;
1335*49ef7e06SGarrett D'Amore 
1336*49ef7e06SGarrett D'Amore 	(void) ddi_dma_sync(stbp->stb_esm.esm_dma_handle,
1337*49ef7e06SGarrett D'Amore 	    stbp->stb_off, ebp->eb_size,
1338*49ef7e06SGarrett D'Amore 	    DDI_DMA_SYNC_FORDEV);
1339*49ef7e06SGarrett D'Amore 
1340*49ef7e06SGarrett D'Amore 	stbp->stb_off = stbp->stb_esm.esm_used;
1341*49ef7e06SGarrett D'Amore 
1342*49ef7e06SGarrett D'Amore 	DTRACE_PROBE5(tx_buffer_add,
1343*49ef7e06SGarrett D'Amore 	    unsigned int, stp->st_index,
1344*49ef7e06SGarrett D'Amore 	    unsigned int, stp->st_n - 1,
1345*49ef7e06SGarrett D'Amore 	    uint64_t, ebp->eb_addr, size_t, ebp->eb_size,
1346*49ef7e06SGarrett D'Amore 	    boolean_t, ebp->eb_eop);
1347*49ef7e06SGarrett D'Amore 
1348*49ef7e06SGarrett D'Amore 	return (0);
1349*49ef7e06SGarrett D'Amore 
1350*49ef7e06SGarrett D'Amore fail1:
1351*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1352*49ef7e06SGarrett D'Amore 
1353*49ef7e06SGarrett D'Amore 	return (rc);
1354*49ef7e06SGarrett D'Amore }
1355*49ef7e06SGarrett D'Amore 
1356*49ef7e06SGarrett D'Amore static inline boolean_t
sfxge_tx_msgb_copy(mblk_t * mp,sfxge_tx_buffer_t * stbp,size_t * offp,size_t * limitp)1357*49ef7e06SGarrett D'Amore sfxge_tx_msgb_copy(mblk_t *mp, sfxge_tx_buffer_t *stbp, size_t *offp,
1358*49ef7e06SGarrett D'Amore     size_t *limitp)
1359*49ef7e06SGarrett D'Amore {
1360*49ef7e06SGarrett D'Amore 	size_t data_off;
1361*49ef7e06SGarrett D'Amore 	size_t data_size;
1362*49ef7e06SGarrett D'Amore 	size_t copy_off;
1363*49ef7e06SGarrett D'Amore 	size_t copy_size;
1364*49ef7e06SGarrett D'Amore 	boolean_t eop;
1365*49ef7e06SGarrett D'Amore 
1366*49ef7e06SGarrett D'Amore 	ASSERT3U(*offp, <=, MBLKL(mp));
1367*49ef7e06SGarrett D'Amore 	ASSERT(*limitp != 0);
1368*49ef7e06SGarrett D'Amore 
1369*49ef7e06SGarrett D'Amore 	data_off = *offp;
1370*49ef7e06SGarrett D'Amore 	data_size = MBLKL(mp) - *offp;
1371*49ef7e06SGarrett D'Amore 
1372*49ef7e06SGarrett D'Amore 	copy_off = stbp->stb_esm.esm_used;
1373*49ef7e06SGarrett D'Amore 	copy_size = SFXGE_TX_BUFFER_SIZE - copy_off;
1374*49ef7e06SGarrett D'Amore 
1375*49ef7e06SGarrett D'Amore 	copy_size = MIN(copy_size, data_size);
1376*49ef7e06SGarrett D'Amore 	copy_size = MIN(copy_size, *limitp);
1377*49ef7e06SGarrett D'Amore 
1378*49ef7e06SGarrett D'Amore 	bcopy(mp->b_rptr + data_off,
1379*49ef7e06SGarrett D'Amore 	    stbp->stb_esm.esm_base + copy_off, copy_size);
1380*49ef7e06SGarrett D'Amore 
1381*49ef7e06SGarrett D'Amore 	stbp->stb_esm.esm_used += copy_size;
1382*49ef7e06SGarrett D'Amore 	ASSERT3U(stbp->stb_esm.esm_used, <=,
1383*49ef7e06SGarrett D'Amore 	    SFXGE_TX_BUFFER_SIZE);
1384*49ef7e06SGarrett D'Amore 
1385*49ef7e06SGarrett D'Amore 	*offp += copy_size;
1386*49ef7e06SGarrett D'Amore 	*limitp -= copy_size;
1387*49ef7e06SGarrett D'Amore 
1388*49ef7e06SGarrett D'Amore 	data_off += copy_size;
1389*49ef7e06SGarrett D'Amore 	data_size -= copy_size;
1390*49ef7e06SGarrett D'Amore 
1391*49ef7e06SGarrett D'Amore 	eop = (*limitp == 0 ||
1392*49ef7e06SGarrett D'Amore 	    (data_size == 0 && mp->b_cont == NULL));
1393*49ef7e06SGarrett D'Amore 
1394*49ef7e06SGarrett D'Amore 	ASSERT3U(*offp, <=, MBLKL(mp));
1395*49ef7e06SGarrett D'Amore 
1396*49ef7e06SGarrett D'Amore 	return (eop);
1397*49ef7e06SGarrett D'Amore }
1398*49ef7e06SGarrett D'Amore 
1399*49ef7e06SGarrett D'Amore static int
sfxge_tx_qpayload_fragment(sfxge_txq_t * stp,unsigned int id,mblk_t ** mpp,size_t * offp,size_t size,boolean_t copy)1400*49ef7e06SGarrett D'Amore sfxge_tx_qpayload_fragment(sfxge_txq_t *stp, unsigned int id, mblk_t **mpp,
1401*49ef7e06SGarrett D'Amore     size_t *offp, size_t size, boolean_t copy)
1402*49ef7e06SGarrett D'Amore {
1403*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
1404*49ef7e06SGarrett D'Amore 	mblk_t *mp = *mpp;
1405*49ef7e06SGarrett D'Amore 	size_t off = *offp;
1406*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp;
1407*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp;
1408*49ef7e06SGarrett D'Amore 	int rc;
1409*49ef7e06SGarrett D'Amore 
1410*49ef7e06SGarrett D'Amore 	stbp = stp->st_stbp[id];
1411*49ef7e06SGarrett D'Amore 	ASSERT(stbp == NULL || (stbp->stb_esm.esm_used == stbp->stb_off));
1412*49ef7e06SGarrett D'Amore 
1413*49ef7e06SGarrett D'Amore 	stmp = stp->st_stmp[id];
1414*49ef7e06SGarrett D'Amore 
1415*49ef7e06SGarrett D'Amore 	while (size != 0) {
1416*49ef7e06SGarrett D'Amore 		boolean_t eop;
1417*49ef7e06SGarrett D'Amore 
1418*49ef7e06SGarrett D'Amore 		ASSERT(mp != NULL);
1419*49ef7e06SGarrett D'Amore 
1420*49ef7e06SGarrett D'Amore 		if (mp->b_cont != NULL)
1421*49ef7e06SGarrett D'Amore 			prefetch_read_many(mp->b_cont);
1422*49ef7e06SGarrett D'Amore 
1423*49ef7e06SGarrett D'Amore 		ASSERT3U(off, <, MBLKL(mp));
1424*49ef7e06SGarrett D'Amore 
1425*49ef7e06SGarrett D'Amore 		if (copy)
1426*49ef7e06SGarrett D'Amore 			goto copy;
1427*49ef7e06SGarrett D'Amore 
1428*49ef7e06SGarrett D'Amore 		/*
1429*49ef7e06SGarrett D'Amore 		 * Check whether we have already mapped this data block for
1430*49ef7e06SGarrett D'Amore 		 * DMA.
1431*49ef7e06SGarrett D'Amore 		 */
1432*49ef7e06SGarrett D'Amore 		if (stmp == NULL || stmp->stm_mp != mp) {
1433*49ef7e06SGarrett D'Amore 			/*
1434*49ef7e06SGarrett D'Amore 			 * If we are part way through copying a data block then
1435*49ef7e06SGarrett D'Amore 			 * there's no point in trying to map it for DMA.
1436*49ef7e06SGarrett D'Amore 			 */
1437*49ef7e06SGarrett D'Amore 			if (off != 0)
1438*49ef7e06SGarrett D'Amore 				goto copy;
1439*49ef7e06SGarrett D'Amore 
1440*49ef7e06SGarrett D'Amore 			/*
1441*49ef7e06SGarrett D'Amore 			 * If the data block is too short then the cost of
1442*49ef7e06SGarrett D'Amore 			 * mapping it for DMA would outweigh the cost of
1443*49ef7e06SGarrett D'Amore 			 * copying it.
1444*49ef7e06SGarrett D'Amore 			 */
1445*49ef7e06SGarrett D'Amore 			if (MBLKL(mp) < SFXGE_TX_COPY_THRESHOLD)
1446*49ef7e06SGarrett D'Amore 				goto copy;
1447*49ef7e06SGarrett D'Amore 
1448*49ef7e06SGarrett D'Amore 			/* Try to grab a transmit mapping from the pool */
1449*49ef7e06SGarrett D'Amore 			stmp = sfxge_tx_qfmp_get(stp);
1450*49ef7e06SGarrett D'Amore 			if (stmp == NULL) {
1451*49ef7e06SGarrett D'Amore 				/*
1452*49ef7e06SGarrett D'Amore 				 * The pool was empty so allocate a new
1453*49ef7e06SGarrett D'Amore 				 * mapping.
1454*49ef7e06SGarrett D'Amore 				 */
1455*49ef7e06SGarrett D'Amore 				if ((stmp = kmem_cache_alloc(sp->s_tmc,
1456*49ef7e06SGarrett D'Amore 				    KM_NOSLEEP)) == NULL)
1457*49ef7e06SGarrett D'Amore 					goto copy;
1458*49ef7e06SGarrett D'Amore 			}
1459*49ef7e06SGarrett D'Amore 
1460*49ef7e06SGarrett D'Amore 			/* Add the DMA mapping to the list */
1461*49ef7e06SGarrett D'Amore 			stmp->stm_next = stp->st_stmp[id];
1462*49ef7e06SGarrett D'Amore 			stp->st_stmp[id] = stmp;
1463*49ef7e06SGarrett D'Amore 
1464*49ef7e06SGarrett D'Amore 			/* Try to bind the data block to the mapping */
1465*49ef7e06SGarrett D'Amore 			if (sfxge_tx_msgb_bind(mp, stmp) != 0)
1466*49ef7e06SGarrett D'Amore 				goto copy;
1467*49ef7e06SGarrett D'Amore 		}
1468*49ef7e06SGarrett D'Amore 		ASSERT3P(stmp->stm_mp, ==, mp);
1469*49ef7e06SGarrett D'Amore 
1470*49ef7e06SGarrett D'Amore 		/*
1471*49ef7e06SGarrett D'Amore 		 * If we have a partially filled buffer then we must add it to
1472*49ef7e06SGarrett D'Amore 		 * the fragment list before adding the mapping.
1473*49ef7e06SGarrett D'Amore 		 */
1474*49ef7e06SGarrett D'Amore 		if (stbp != NULL && (stbp->stb_esm.esm_used > stbp->stb_off)) {
1475*49ef7e06SGarrett D'Amore 			rc = sfxge_tx_qbuffer_add(stp, stbp, B_FALSE);
1476*49ef7e06SGarrett D'Amore 			if (rc != 0)
1477*49ef7e06SGarrett D'Amore 				goto fail1;
1478*49ef7e06SGarrett D'Amore 		}
1479*49ef7e06SGarrett D'Amore 
1480*49ef7e06SGarrett D'Amore 		/* Add the mapping to the fragment list */
1481*49ef7e06SGarrett D'Amore 		rc = sfxge_tx_qmapping_add(stp, stmp, &off, &size);
1482*49ef7e06SGarrett D'Amore 		if (rc != 0)
1483*49ef7e06SGarrett D'Amore 			goto fail2;
1484*49ef7e06SGarrett D'Amore 
1485*49ef7e06SGarrett D'Amore 		ASSERT(off == MBLKL(mp) || size == 0);
1486*49ef7e06SGarrett D'Amore 
1487*49ef7e06SGarrett D'Amore 		/*
1488*49ef7e06SGarrett D'Amore 		 * If the data block has been exhausted then Skip over the
1489*49ef7e06SGarrett D'Amore 		 * control block and advance to the next data block.
1490*49ef7e06SGarrett D'Amore 		 */
1491*49ef7e06SGarrett D'Amore 		if (off == MBLKL(mp)) {
1492*49ef7e06SGarrett D'Amore 			mp = mp->b_cont;
1493*49ef7e06SGarrett D'Amore 			off = 0;
1494*49ef7e06SGarrett D'Amore 		}
1495*49ef7e06SGarrett D'Amore 
1496*49ef7e06SGarrett D'Amore 		continue;
1497*49ef7e06SGarrett D'Amore 
1498*49ef7e06SGarrett D'Amore copy:
1499*49ef7e06SGarrett D'Amore 		if (stbp == NULL ||
1500*49ef7e06SGarrett D'Amore 		    stbp->stb_esm.esm_used == SFXGE_TX_BUFFER_SIZE) {
1501*49ef7e06SGarrett D'Amore 			/* Try to grab a buffer from the pool */
1502*49ef7e06SGarrett D'Amore 			stbp = sfxge_tx_qfbp_get(stp);
1503*49ef7e06SGarrett D'Amore 			if (stbp == NULL) {
1504*49ef7e06SGarrett D'Amore 				/*
1505*49ef7e06SGarrett D'Amore 				 * The pool was empty so allocate a new
1506*49ef7e06SGarrett D'Amore 				 * buffer.
1507*49ef7e06SGarrett D'Amore 				 */
1508*49ef7e06SGarrett D'Amore 				if ((stbp = kmem_cache_alloc(sp->s_tbc,
1509*49ef7e06SGarrett D'Amore 				    KM_NOSLEEP)) == NULL) {
1510*49ef7e06SGarrett D'Amore 					rc = ENOMEM;
1511*49ef7e06SGarrett D'Amore 					goto fail3;
1512*49ef7e06SGarrett D'Amore 				}
1513*49ef7e06SGarrett D'Amore 			}
1514*49ef7e06SGarrett D'Amore 
1515*49ef7e06SGarrett D'Amore 			/* Add it to the list */
1516*49ef7e06SGarrett D'Amore 			stbp->stb_next = stp->st_stbp[id];
1517*49ef7e06SGarrett D'Amore 			stp->st_stbp[id] = stbp;
1518*49ef7e06SGarrett D'Amore 		}
1519*49ef7e06SGarrett D'Amore 
1520*49ef7e06SGarrett D'Amore 		/* Copy as much of the data block as we can into the buffer */
1521*49ef7e06SGarrett D'Amore 		eop = sfxge_tx_msgb_copy(mp, stbp, &off, &size);
1522*49ef7e06SGarrett D'Amore 
1523*49ef7e06SGarrett D'Amore 		ASSERT(off == MBLKL(mp) || size == 0 ||
1524*49ef7e06SGarrett D'Amore 		    stbp->stb_esm.esm_used == SFXGE_TX_BUFFER_SIZE);
1525*49ef7e06SGarrett D'Amore 
1526*49ef7e06SGarrett D'Amore 		/*
1527*49ef7e06SGarrett D'Amore 		 * If we have reached the end of the packet, or the buffer is
1528*49ef7e06SGarrett D'Amore 		 * full, then add the buffer to the fragment list.
1529*49ef7e06SGarrett D'Amore 		 */
1530*49ef7e06SGarrett D'Amore 		if (stbp->stb_esm.esm_used == SFXGE_TX_BUFFER_SIZE || eop) {
1531*49ef7e06SGarrett D'Amore 			rc = sfxge_tx_qbuffer_add(stp, stbp, eop);
1532*49ef7e06SGarrett D'Amore 			if (rc != 0)
1533*49ef7e06SGarrett D'Amore 				goto fail4;
1534*49ef7e06SGarrett D'Amore 		}
1535*49ef7e06SGarrett D'Amore 
1536*49ef7e06SGarrett D'Amore 		/*
1537*49ef7e06SGarrett D'Amore 		 * If the data block has been exhaused then advance to the next
1538*49ef7e06SGarrett D'Amore 		 * one.
1539*49ef7e06SGarrett D'Amore 		 */
1540*49ef7e06SGarrett D'Amore 		if (off == MBLKL(mp)) {
1541*49ef7e06SGarrett D'Amore 			mp = mp->b_cont;
1542*49ef7e06SGarrett D'Amore 			off = 0;
1543*49ef7e06SGarrett D'Amore 		}
1544*49ef7e06SGarrett D'Amore 	}
1545*49ef7e06SGarrett D'Amore 
1546*49ef7e06SGarrett D'Amore 	*mpp = mp;
1547*49ef7e06SGarrett D'Amore 	*offp = off;
1548*49ef7e06SGarrett D'Amore 
1549*49ef7e06SGarrett D'Amore 	return (0);
1550*49ef7e06SGarrett D'Amore 
1551*49ef7e06SGarrett D'Amore fail4:
1552*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
1553*49ef7e06SGarrett D'Amore fail3:
1554*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
1555*49ef7e06SGarrett D'Amore fail2:
1556*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1557*49ef7e06SGarrett D'Amore fail1:
1558*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1559*49ef7e06SGarrett D'Amore 
1560*49ef7e06SGarrett D'Amore 	return (rc);
1561*49ef7e06SGarrett D'Amore }
1562*49ef7e06SGarrett D'Amore 
1563*49ef7e06SGarrett D'Amore static int
sfxge_tx_qlso_fragment(sfxge_txq_t * stp,sfxge_tx_packet_t * stpp,boolean_t copy)1564*49ef7e06SGarrett D'Amore sfxge_tx_qlso_fragment(sfxge_txq_t *stp, sfxge_tx_packet_t *stpp,
1565*49ef7e06SGarrett D'Amore     boolean_t copy)
1566*49ef7e06SGarrett D'Amore {
1567*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
1568*49ef7e06SGarrett D'Amore 	mblk_t *mp = stpp->stp_mp;
1569*49ef7e06SGarrett D'Amore 	struct ether_header *etherhp = stpp->stp_etherhp;
1570*49ef7e06SGarrett D'Amore 	struct ip *iphp = stpp->stp_iphp;
1571*49ef7e06SGarrett D'Amore 	struct tcphdr *thp = stpp->stp_thp;
1572*49ef7e06SGarrett D'Amore 	size_t size = stpp->stp_size;
1573*49ef7e06SGarrett D'Amore 	size_t off = stpp->stp_off;
1574*49ef7e06SGarrett D'Amore 	size_t mss = stpp->stp_mss;
1575*49ef7e06SGarrett D'Amore 	unsigned int id;
1576*49ef7e06SGarrett D'Amore 	caddr_t hp;
1577*49ef7e06SGarrett D'Amore 	size_t ehs, hs;
1578*49ef7e06SGarrett D'Amore 	uint16_t start_len;
1579*49ef7e06SGarrett D'Amore 	uint16_t start_id;
1580*49ef7e06SGarrett D'Amore 	uint16_t ip_id;
1581*49ef7e06SGarrett D'Amore 	uint8_t start_flags;
1582*49ef7e06SGarrett D'Amore 	uint32_t start_seq;
1583*49ef7e06SGarrett D'Amore 	uint32_t th_seq;
1584*49ef7e06SGarrett D'Amore 	size_t lss;
1585*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp;
1586*49ef7e06SGarrett D'Amore 	int rc;
1587*49ef7e06SGarrett D'Amore 
1588*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
1589*49ef7e06SGarrett D'Amore 
1590*49ef7e06SGarrett D'Amore 	if ((DB_LSOFLAGS(mp) & HW_LSO) == 0) {
1591*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1592*49ef7e06SGarrett D'Amore 		goto fail1;
1593*49ef7e06SGarrett D'Amore 	}
1594*49ef7e06SGarrett D'Amore 
1595*49ef7e06SGarrett D'Amore 	id = stp->st_added & (SFXGE_TX_NDESCS - 1);
1596*49ef7e06SGarrett D'Amore 
1597*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_n == 0);
1598*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_stbp[id] == NULL);
1599*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_stmp[id] == NULL);
1600*49ef7e06SGarrett D'Amore 
1601*49ef7e06SGarrett D'Amore 	ehs = (etherhp->ether_type == htons(ETHERTYPE_VLAN)) ?
1602*49ef7e06SGarrett D'Amore 	    sizeof (struct ether_vlan_header) :
1603*49ef7e06SGarrett D'Amore 	    sizeof (struct ether_header);
1604*49ef7e06SGarrett D'Amore 	if (msgdsize(mp) != ehs + ntohs(iphp->ip_len)) {
1605*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1606*49ef7e06SGarrett D'Amore 		goto fail2;
1607*49ef7e06SGarrett D'Amore 	}
1608*49ef7e06SGarrett D'Amore 
1609*49ef7e06SGarrett D'Amore 	/* The payload offset is equivalent to the size of the headers */
1610*49ef7e06SGarrett D'Amore 	hp = (caddr_t)(mp->b_rptr);
1611*49ef7e06SGarrett D'Amore 	hs = off;
1612*49ef7e06SGarrett D'Amore 
1613*49ef7e06SGarrett D'Amore 	/*
1614*49ef7e06SGarrett D'Amore 	 * If the initial data block only contains the headers then advance
1615*49ef7e06SGarrett D'Amore 	 * to the next one.
1616*49ef7e06SGarrett D'Amore 	 */
1617*49ef7e06SGarrett D'Amore 	if (hs > MBLKL(mp)) {
1618*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1619*49ef7e06SGarrett D'Amore 		goto fail3;
1620*49ef7e06SGarrett D'Amore 	}
1621*49ef7e06SGarrett D'Amore 	mp->b_rptr += hs;
1622*49ef7e06SGarrett D'Amore 
1623*49ef7e06SGarrett D'Amore 	if (MBLKL(mp) == 0)
1624*49ef7e06SGarrett D'Amore 		mp = mp->b_cont;
1625*49ef7e06SGarrett D'Amore 
1626*49ef7e06SGarrett D'Amore 	off = 0;
1627*49ef7e06SGarrett D'Amore 
1628*49ef7e06SGarrett D'Amore 	/* Check IP and TCP headers are suitable for LSO */
1629*49ef7e06SGarrett D'Amore 	if (((iphp->ip_off & ~htons(IP_DF)) != 0) ||
1630*49ef7e06SGarrett D'Amore 	    ((thp->th_flags & (TH_URG | TH_SYN)) != 0) ||
1631*49ef7e06SGarrett D'Amore 	    (thp->th_urp != 0)) {
1632*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1633*49ef7e06SGarrett D'Amore 		goto fail4;
1634*49ef7e06SGarrett D'Amore 	}
1635*49ef7e06SGarrett D'Amore 
1636*49ef7e06SGarrett D'Amore 	if (size + (thp->th_off << 2) + (iphp->ip_hl << 2) !=
1637*49ef7e06SGarrett D'Amore 	    ntohs(iphp->ip_len)) {
1638*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1639*49ef7e06SGarrett D'Amore 		goto fail4;
1640*49ef7e06SGarrett D'Amore 	}
1641*49ef7e06SGarrett D'Amore 
1642*49ef7e06SGarrett D'Amore 	/*
1643*49ef7e06SGarrett D'Amore 	 * Get the base IP id, The stack leaves enough of a gap in id space
1644*49ef7e06SGarrett D'Amore 	 * for us to increment this for each segment we send out.
1645*49ef7e06SGarrett D'Amore 	 */
1646*49ef7e06SGarrett D'Amore 	start_len = ntohs(iphp->ip_len);
1647*49ef7e06SGarrett D'Amore 	start_id = ip_id = ntohs(iphp->ip_id);
1648*49ef7e06SGarrett D'Amore 
1649*49ef7e06SGarrett D'Amore 	/* Get the base TCP sequence number and flags */
1650*49ef7e06SGarrett D'Amore 	start_flags = thp->th_flags;
1651*49ef7e06SGarrett D'Amore 	start_seq = th_seq = ntohl(thp->th_seq);
1652*49ef7e06SGarrett D'Amore 
1653*49ef7e06SGarrett D'Amore 	/* Adjust the header for interim segments */
1654*49ef7e06SGarrett D'Amore 	iphp->ip_len = htons((iphp->ip_hl << 2) + (thp->th_off << 2) + mss);
1655*49ef7e06SGarrett D'Amore 	thp->th_flags = start_flags & ~(TH_PUSH | TH_FIN);
1656*49ef7e06SGarrett D'Amore 
1657*49ef7e06SGarrett D'Amore 	lss = size;
1658*49ef7e06SGarrett D'Amore 	if ((lss / mss) >= (EFX_TXQ_LIMIT(SFXGE_TX_NDESCS) / 2)) {
1659*49ef7e06SGarrett D'Amore 		rc = EINVAL;
1660*49ef7e06SGarrett D'Amore 		goto fail5;
1661*49ef7e06SGarrett D'Amore 	}
1662*49ef7e06SGarrett D'Amore 
1663*49ef7e06SGarrett D'Amore 	stbp = NULL;
1664*49ef7e06SGarrett D'Amore 	while (lss != 0) {
1665*49ef7e06SGarrett D'Amore 		size_t ss = MIN(lss, mss);
1666*49ef7e06SGarrett D'Amore 		boolean_t eol = (ss == lss);
1667*49ef7e06SGarrett D'Amore 
1668*49ef7e06SGarrett D'Amore 		/* Adjust the header for this segment */
1669*49ef7e06SGarrett D'Amore 		iphp->ip_id = htons(ip_id);
1670*49ef7e06SGarrett D'Amore 		ip_id++;
1671*49ef7e06SGarrett D'Amore 
1672*49ef7e06SGarrett D'Amore 		thp->th_seq = htonl(th_seq);
1673*49ef7e06SGarrett D'Amore 		th_seq += ss;
1674*49ef7e06SGarrett D'Amore 
1675*49ef7e06SGarrett D'Amore 		/* If this is the final segment then do some extra adjustment */
1676*49ef7e06SGarrett D'Amore 		if (eol) {
1677*49ef7e06SGarrett D'Amore 			iphp->ip_len = htons((iphp->ip_hl << 2) +
1678*49ef7e06SGarrett D'Amore 			    (thp->th_off << 2) + ss);
1679*49ef7e06SGarrett D'Amore 			thp->th_flags = start_flags;
1680*49ef7e06SGarrett D'Amore 		}
1681*49ef7e06SGarrett D'Amore 
1682*49ef7e06SGarrett D'Amore 		if (stbp == NULL ||
1683*49ef7e06SGarrett D'Amore 		    stbp->stb_esm.esm_used + hs > SFXGE_TX_BUFFER_SIZE) {
1684*49ef7e06SGarrett D'Amore 			/* Try to grab a buffer from the pool */
1685*49ef7e06SGarrett D'Amore 			stbp = sfxge_tx_qfbp_get(stp);
1686*49ef7e06SGarrett D'Amore 			if (stbp == NULL) {
1687*49ef7e06SGarrett D'Amore 				/*
1688*49ef7e06SGarrett D'Amore 				 * The pool was empty so allocate a new
1689*49ef7e06SGarrett D'Amore 				 * buffer.
1690*49ef7e06SGarrett D'Amore 				 */
1691*49ef7e06SGarrett D'Amore 				if ((stbp = kmem_cache_alloc(sp->s_tbc,
1692*49ef7e06SGarrett D'Amore 				    KM_NOSLEEP)) == NULL) {
1693*49ef7e06SGarrett D'Amore 					rc = ENOMEM;
1694*49ef7e06SGarrett D'Amore 					goto fail6;
1695*49ef7e06SGarrett D'Amore 				}
1696*49ef7e06SGarrett D'Amore 			}
1697*49ef7e06SGarrett D'Amore 
1698*49ef7e06SGarrett D'Amore 			/* Add it to the list */
1699*49ef7e06SGarrett D'Amore 			stbp->stb_next = stp->st_stbp[id];
1700*49ef7e06SGarrett D'Amore 			stp->st_stbp[id] = stbp;
1701*49ef7e06SGarrett D'Amore 		}
1702*49ef7e06SGarrett D'Amore 
1703*49ef7e06SGarrett D'Amore 		/* Copy in the headers */
1704*49ef7e06SGarrett D'Amore 		ASSERT3U(stbp->stb_off, ==, stbp->stb_esm.esm_used);
1705*49ef7e06SGarrett D'Amore 		bcopy(hp, stbp->stb_esm.esm_base + stbp->stb_off, hs);
1706*49ef7e06SGarrett D'Amore 		stbp->stb_esm.esm_used += hs;
1707*49ef7e06SGarrett D'Amore 
1708*49ef7e06SGarrett D'Amore 		/* Add the buffer to the fragment list */
1709*49ef7e06SGarrett D'Amore 		rc = sfxge_tx_qbuffer_add(stp, stbp, B_FALSE);
1710*49ef7e06SGarrett D'Amore 		if (rc != 0)
1711*49ef7e06SGarrett D'Amore 			goto fail7;
1712*49ef7e06SGarrett D'Amore 
1713*49ef7e06SGarrett D'Amore 		/* Add the payload to the fragment list */
1714*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_tx_qpayload_fragment(stp, id, &mp, &off,
1715*49ef7e06SGarrett D'Amore 		    ss, copy)) != 0)
1716*49ef7e06SGarrett D'Amore 			goto fail8;
1717*49ef7e06SGarrett D'Amore 
1718*49ef7e06SGarrett D'Amore 		lss -= ss;
1719*49ef7e06SGarrett D'Amore 	}
1720*49ef7e06SGarrett D'Amore 	ASSERT3U(off, ==, 0);
1721*49ef7e06SGarrett D'Amore 	ASSERT3P(mp, ==, NULL);
1722*49ef7e06SGarrett D'Amore 
1723*49ef7e06SGarrett D'Amore 	ASSERT3U(th_seq - start_seq, ==, size);
1724*49ef7e06SGarrett D'Amore 
1725*49ef7e06SGarrett D'Amore 	/*
1726*49ef7e06SGarrett D'Amore 	 * If no part of the packet has been mapped for DMA then we can free
1727*49ef7e06SGarrett D'Amore 	 * it now, otherwise it can only be freed on completion.
1728*49ef7e06SGarrett D'Amore 	 */
1729*49ef7e06SGarrett D'Amore 	if (stp->st_stmp[id] == NULL)
1730*49ef7e06SGarrett D'Amore 		freemsg(stpp->stp_mp);
1731*49ef7e06SGarrett D'Amore 	else
1732*49ef7e06SGarrett D'Amore 		stp->st_mp[id] = stpp->stp_mp;
1733*49ef7e06SGarrett D'Amore 
1734*49ef7e06SGarrett D'Amore 	stpp->stp_mp = NULL;
1735*49ef7e06SGarrett D'Amore 
1736*49ef7e06SGarrett D'Amore 	return (0);
1737*49ef7e06SGarrett D'Amore 
1738*49ef7e06SGarrett D'Amore fail8:
1739*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail8);
1740*49ef7e06SGarrett D'Amore fail7:
1741*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail7);
1742*49ef7e06SGarrett D'Amore fail6:
1743*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail6);
1744*49ef7e06SGarrett D'Amore fail5:
1745*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail5);
1746*49ef7e06SGarrett D'Amore 
1747*49ef7e06SGarrett D'Amore 	/* Restore the header */
1748*49ef7e06SGarrett D'Amore 	thp->th_seq = htonl(start_seq);
1749*49ef7e06SGarrett D'Amore 	thp->th_flags = start_flags;
1750*49ef7e06SGarrett D'Amore 
1751*49ef7e06SGarrett D'Amore 	iphp->ip_len = htons(start_len);
1752*49ef7e06SGarrett D'Amore 	iphp->ip_id = htons(start_id);
1753*49ef7e06SGarrett D'Amore 
1754*49ef7e06SGarrett D'Amore fail4:
1755*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
1756*49ef7e06SGarrett D'Amore 
1757*49ef7e06SGarrett D'Amore 	mp = stpp->stp_mp;
1758*49ef7e06SGarrett D'Amore 	mp->b_rptr -= hs;
1759*49ef7e06SGarrett D'Amore 
1760*49ef7e06SGarrett D'Amore 	ASSERT3U(((etherhp->ether_type == htons(ETHERTYPE_VLAN)) ?
1761*49ef7e06SGarrett D'Amore 	    sizeof (struct ether_vlan_header) :
1762*49ef7e06SGarrett D'Amore 	    sizeof (struct ether_header)) +
1763*49ef7e06SGarrett D'Amore 	    ntohs(iphp->ip_len), ==, msgdsize(mp));
1764*49ef7e06SGarrett D'Amore 
1765*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_mp[id] == NULL);
1766*49ef7e06SGarrett D'Amore 
1767*49ef7e06SGarrett D'Amore fail3:
1768*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
1769*49ef7e06SGarrett D'Amore fail2:
1770*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1771*49ef7e06SGarrett D'Amore fail1:
1772*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1773*49ef7e06SGarrett D'Amore 
1774*49ef7e06SGarrett D'Amore 	return (rc);
1775*49ef7e06SGarrett D'Amore }
1776*49ef7e06SGarrett D'Amore 
1777*49ef7e06SGarrett D'Amore static int
sfxge_tx_qpacket_fragment(sfxge_txq_t * stp,sfxge_tx_packet_t * stpp,boolean_t copy)1778*49ef7e06SGarrett D'Amore sfxge_tx_qpacket_fragment(sfxge_txq_t *stp, sfxge_tx_packet_t *stpp,
1779*49ef7e06SGarrett D'Amore     boolean_t copy)
1780*49ef7e06SGarrett D'Amore {
1781*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
1782*49ef7e06SGarrett D'Amore 	mblk_t *mp = stpp->stp_mp;
1783*49ef7e06SGarrett D'Amore 	unsigned int id;
1784*49ef7e06SGarrett D'Amore 	size_t off;
1785*49ef7e06SGarrett D'Amore 	size_t size;
1786*49ef7e06SGarrett D'Amore 	sfxge_tx_mapping_t *stmp;
1787*49ef7e06SGarrett D'Amore 	sfxge_tx_buffer_t *stbp;
1788*49ef7e06SGarrett D'Amore 	int rc;
1789*49ef7e06SGarrett D'Amore 
1790*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
1791*49ef7e06SGarrett D'Amore 
1792*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_n == 0);
1793*49ef7e06SGarrett D'Amore 
1794*49ef7e06SGarrett D'Amore 	id = stp->st_added & (SFXGE_TX_NDESCS - 1);
1795*49ef7e06SGarrett D'Amore 
1796*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_stbp[id] == NULL);
1797*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_stmp[id] == NULL);
1798*49ef7e06SGarrett D'Amore 
1799*49ef7e06SGarrett D'Amore 	off = 0;
1800*49ef7e06SGarrett D'Amore 	size = LONG_MAX;	/* must be larger than the packet */
1801*49ef7e06SGarrett D'Amore 
1802*49ef7e06SGarrett D'Amore 	stbp = NULL;
1803*49ef7e06SGarrett D'Amore 	stmp = NULL;
1804*49ef7e06SGarrett D'Amore 
1805*49ef7e06SGarrett D'Amore 	while (mp != NULL) {
1806*49ef7e06SGarrett D'Amore 		boolean_t eop;
1807*49ef7e06SGarrett D'Amore 
1808*49ef7e06SGarrett D'Amore 		ASSERT(mp != NULL);
1809*49ef7e06SGarrett D'Amore 
1810*49ef7e06SGarrett D'Amore 		if (mp->b_cont != NULL)
1811*49ef7e06SGarrett D'Amore 			prefetch_read_many(mp->b_cont);
1812*49ef7e06SGarrett D'Amore 
1813*49ef7e06SGarrett D'Amore 		ASSERT(stmp == NULL || stmp->stm_mp != mp);
1814*49ef7e06SGarrett D'Amore 
1815*49ef7e06SGarrett D'Amore 		if (copy)
1816*49ef7e06SGarrett D'Amore 			goto copy;
1817*49ef7e06SGarrett D'Amore 
1818*49ef7e06SGarrett D'Amore 		/*
1819*49ef7e06SGarrett D'Amore 		 * If we are part way through copying a data block then there's
1820*49ef7e06SGarrett D'Amore 		 * no point in trying to map it for DMA.
1821*49ef7e06SGarrett D'Amore 		 */
1822*49ef7e06SGarrett D'Amore 		if (off != 0)
1823*49ef7e06SGarrett D'Amore 			goto copy;
1824*49ef7e06SGarrett D'Amore 
1825*49ef7e06SGarrett D'Amore 		/*
1826*49ef7e06SGarrett D'Amore 		 * If the data block is too short then the cost of mapping it
1827*49ef7e06SGarrett D'Amore 		 * for DMA would outweigh the cost of copying it.
1828*49ef7e06SGarrett D'Amore 		 *
1829*49ef7e06SGarrett D'Amore 		 * TX copy break
1830*49ef7e06SGarrett D'Amore 		 */
1831*49ef7e06SGarrett D'Amore 		if (MBLKL(mp) < SFXGE_TX_COPY_THRESHOLD)
1832*49ef7e06SGarrett D'Amore 			goto copy;
1833*49ef7e06SGarrett D'Amore 
1834*49ef7e06SGarrett D'Amore 		/* Try to grab a transmit mapping from the pool */
1835*49ef7e06SGarrett D'Amore 		stmp = sfxge_tx_qfmp_get(stp);
1836*49ef7e06SGarrett D'Amore 		if (stmp == NULL) {
1837*49ef7e06SGarrett D'Amore 			/*
1838*49ef7e06SGarrett D'Amore 			 * The pool was empty so allocate a new
1839*49ef7e06SGarrett D'Amore 			 * mapping.
1840*49ef7e06SGarrett D'Amore 			 */
1841*49ef7e06SGarrett D'Amore 			if ((stmp = kmem_cache_alloc(sp->s_tmc,
1842*49ef7e06SGarrett D'Amore 			    KM_NOSLEEP)) == NULL)
1843*49ef7e06SGarrett D'Amore 				goto copy;
1844*49ef7e06SGarrett D'Amore 		}
1845*49ef7e06SGarrett D'Amore 
1846*49ef7e06SGarrett D'Amore 		/* Add the DMA mapping to the list */
1847*49ef7e06SGarrett D'Amore 		stmp->stm_next = stp->st_stmp[id];
1848*49ef7e06SGarrett D'Amore 		stp->st_stmp[id] = stmp;
1849*49ef7e06SGarrett D'Amore 
1850*49ef7e06SGarrett D'Amore 		/* Try to bind the data block to the mapping */
1851*49ef7e06SGarrett D'Amore 		if (sfxge_tx_msgb_bind(mp, stmp) != 0)
1852*49ef7e06SGarrett D'Amore 			goto copy;
1853*49ef7e06SGarrett D'Amore 
1854*49ef7e06SGarrett D'Amore 		/*
1855*49ef7e06SGarrett D'Amore 		 * If we have a partially filled buffer then we must add it to
1856*49ef7e06SGarrett D'Amore 		 * the fragment list before adding the mapping.
1857*49ef7e06SGarrett D'Amore 		 */
1858*49ef7e06SGarrett D'Amore 		if (stbp != NULL && (stbp->stb_esm.esm_used > stbp->stb_off)) {
1859*49ef7e06SGarrett D'Amore 			rc = sfxge_tx_qbuffer_add(stp, stbp, B_FALSE);
1860*49ef7e06SGarrett D'Amore 			if (rc != 0)
1861*49ef7e06SGarrett D'Amore 				goto fail1;
1862*49ef7e06SGarrett D'Amore 		}
1863*49ef7e06SGarrett D'Amore 
1864*49ef7e06SGarrett D'Amore 		/* Add the mapping to the fragment list */
1865*49ef7e06SGarrett D'Amore 		rc = sfxge_tx_qmapping_add(stp, stmp, &off, &size);
1866*49ef7e06SGarrett D'Amore 		if (rc != 0)
1867*49ef7e06SGarrett D'Amore 			goto fail2;
1868*49ef7e06SGarrett D'Amore 
1869*49ef7e06SGarrett D'Amore 		ASSERT3U(off, ==, MBLKL(mp));
1870*49ef7e06SGarrett D'Amore 
1871*49ef7e06SGarrett D'Amore 		/* Advance to the next data block */
1872*49ef7e06SGarrett D'Amore 		mp = mp->b_cont;
1873*49ef7e06SGarrett D'Amore 		off = 0;
1874*49ef7e06SGarrett D'Amore 		continue;
1875*49ef7e06SGarrett D'Amore 
1876*49ef7e06SGarrett D'Amore copy:
1877*49ef7e06SGarrett D'Amore 		if (stbp == NULL ||
1878*49ef7e06SGarrett D'Amore 		    stbp->stb_esm.esm_used == SFXGE_TX_BUFFER_SIZE) {
1879*49ef7e06SGarrett D'Amore 			/* Try to grab a buffer from the pool */
1880*49ef7e06SGarrett D'Amore 			stbp = sfxge_tx_qfbp_get(stp);
1881*49ef7e06SGarrett D'Amore 			if (stbp == NULL) {
1882*49ef7e06SGarrett D'Amore 				/*
1883*49ef7e06SGarrett D'Amore 				 * The pool was empty so allocate a new
1884*49ef7e06SGarrett D'Amore 				 * buffer.
1885*49ef7e06SGarrett D'Amore 				 */
1886*49ef7e06SGarrett D'Amore 				if ((stbp = kmem_cache_alloc(sp->s_tbc,
1887*49ef7e06SGarrett D'Amore 				    KM_NOSLEEP)) == NULL) {
1888*49ef7e06SGarrett D'Amore 					rc = ENOMEM;
1889*49ef7e06SGarrett D'Amore 					goto fail3;
1890*49ef7e06SGarrett D'Amore 				}
1891*49ef7e06SGarrett D'Amore 			}
1892*49ef7e06SGarrett D'Amore 
1893*49ef7e06SGarrett D'Amore 			/* Add it to the list */
1894*49ef7e06SGarrett D'Amore 			stbp->stb_next = stp->st_stbp[id];
1895*49ef7e06SGarrett D'Amore 			stp->st_stbp[id] = stbp;
1896*49ef7e06SGarrett D'Amore 		}
1897*49ef7e06SGarrett D'Amore 
1898*49ef7e06SGarrett D'Amore 		/* Copy as much of the data block as we can into the buffer */
1899*49ef7e06SGarrett D'Amore 		eop = sfxge_tx_msgb_copy(mp, stbp, &off, &size);
1900*49ef7e06SGarrett D'Amore 
1901*49ef7e06SGarrett D'Amore 		ASSERT(off == MBLKL(mp) ||
1902*49ef7e06SGarrett D'Amore 		    stbp->stb_esm.esm_used == SFXGE_TX_BUFFER_SIZE);
1903*49ef7e06SGarrett D'Amore 
1904*49ef7e06SGarrett D'Amore 		/*
1905*49ef7e06SGarrett D'Amore 		 * If we have reached the end of the packet, or the buffer is
1906*49ef7e06SGarrett D'Amore 		 * full, then add the buffer to the fragment list.
1907*49ef7e06SGarrett D'Amore 		 */
1908*49ef7e06SGarrett D'Amore 		if (stbp->stb_esm.esm_used == SFXGE_TX_BUFFER_SIZE || eop) {
1909*49ef7e06SGarrett D'Amore 			rc = sfxge_tx_qbuffer_add(stp, stbp, eop);
1910*49ef7e06SGarrett D'Amore 			if (rc != 0)
1911*49ef7e06SGarrett D'Amore 				goto fail4;
1912*49ef7e06SGarrett D'Amore 		}
1913*49ef7e06SGarrett D'Amore 
1914*49ef7e06SGarrett D'Amore 		/*
1915*49ef7e06SGarrett D'Amore 		 * If the data block has been exhaused then advance to the next
1916*49ef7e06SGarrett D'Amore 		 * one.
1917*49ef7e06SGarrett D'Amore 		 */
1918*49ef7e06SGarrett D'Amore 		if (off == MBLKL(mp)) {
1919*49ef7e06SGarrett D'Amore 			mp = mp->b_cont;
1920*49ef7e06SGarrett D'Amore 			off = 0;
1921*49ef7e06SGarrett D'Amore 		}
1922*49ef7e06SGarrett D'Amore 	}
1923*49ef7e06SGarrett D'Amore 	ASSERT3U(off, ==, 0);
1924*49ef7e06SGarrett D'Amore 	ASSERT3P(mp, ==, NULL);
1925*49ef7e06SGarrett D'Amore 	ASSERT3U(size, !=, 0);
1926*49ef7e06SGarrett D'Amore 
1927*49ef7e06SGarrett D'Amore 	/*
1928*49ef7e06SGarrett D'Amore 	 * If no part of the packet has been mapped for DMA then we can free
1929*49ef7e06SGarrett D'Amore 	 * it now, otherwise it can only be freed on completion.
1930*49ef7e06SGarrett D'Amore 	 */
1931*49ef7e06SGarrett D'Amore 	if (stp->st_stmp[id] == NULL)
1932*49ef7e06SGarrett D'Amore 		freemsg(stpp->stp_mp);
1933*49ef7e06SGarrett D'Amore 	else
1934*49ef7e06SGarrett D'Amore 		stp->st_mp[id] = stpp->stp_mp;
1935*49ef7e06SGarrett D'Amore 
1936*49ef7e06SGarrett D'Amore 	stpp->stp_mp = NULL;
1937*49ef7e06SGarrett D'Amore 
1938*49ef7e06SGarrett D'Amore 	return (0);
1939*49ef7e06SGarrett D'Amore 
1940*49ef7e06SGarrett D'Amore fail4:
1941*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
1942*49ef7e06SGarrett D'Amore fail3:
1943*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
1944*49ef7e06SGarrett D'Amore fail2:
1945*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1946*49ef7e06SGarrett D'Amore fail1:
1947*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1948*49ef7e06SGarrett D'Amore 
1949*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_stmp[id] == NULL);
1950*49ef7e06SGarrett D'Amore 
1951*49ef7e06SGarrett D'Amore 	return (rc);
1952*49ef7e06SGarrett D'Amore }
1953*49ef7e06SGarrett D'Amore 
1954*49ef7e06SGarrett D'Amore 
1955*49ef7e06SGarrett D'Amore #define	SFXGE_TX_QDPL_PUT_PENDING(_stp)					\
1956*49ef7e06SGarrett D'Amore 	((_stp)->st_dpl.std_put != 0)
1957*49ef7e06SGarrett D'Amore 
1958*49ef7e06SGarrett D'Amore static void
sfxge_tx_qdpl_swizzle(sfxge_txq_t * stp)1959*49ef7e06SGarrett D'Amore sfxge_tx_qdpl_swizzle(sfxge_txq_t *stp)
1960*49ef7e06SGarrett D'Amore {
1961*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
1962*49ef7e06SGarrett D'Amore 	volatile uintptr_t *putp;
1963*49ef7e06SGarrett D'Amore 	uintptr_t put;
1964*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
1965*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *p;
1966*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t **pp;
1967*49ef7e06SGarrett D'Amore 	unsigned int count;
1968*49ef7e06SGarrett D'Amore 
1969*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
1970*49ef7e06SGarrett D'Amore 
1971*49ef7e06SGarrett D'Amore 	/*
1972*49ef7e06SGarrett D'Amore 	 * Guaranteed that in flight TX packets will cause more TX completions
1973*49ef7e06SGarrett D'Amore 	 * hence more swizzles must happen
1974*49ef7e06SGarrett D'Amore 	 */
1975*49ef7e06SGarrett D'Amore 	ASSERT3U(stdp->std_count, <=, sfxge_tx_dpl_get_pkt_max(stp));
1976*49ef7e06SGarrett D'Amore 	if (stdp->std_count >= stdp->get_pkt_limit)
1977*49ef7e06SGarrett D'Amore 		return;
1978*49ef7e06SGarrett D'Amore 
1979*49ef7e06SGarrett D'Amore 	/* Acquire the put list - replacing with an empty list */
1980*49ef7e06SGarrett D'Amore 	putp = &(stdp->std_put);
1981*49ef7e06SGarrett D'Amore 	put = atomic_swap_ulong(putp, 0);
1982*49ef7e06SGarrett D'Amore 	stpp = (void *)put;
1983*49ef7e06SGarrett D'Amore 
1984*49ef7e06SGarrett D'Amore 	if (stpp == NULL)
1985*49ef7e06SGarrett D'Amore 		return;
1986*49ef7e06SGarrett D'Amore 
1987*49ef7e06SGarrett D'Amore 	/* Reverse the list */
1988*49ef7e06SGarrett D'Amore 	pp = &(stpp->stp_next);
1989*49ef7e06SGarrett D'Amore 	p = NULL;
1990*49ef7e06SGarrett D'Amore 
1991*49ef7e06SGarrett D'Amore 	count = 0;
1992*49ef7e06SGarrett D'Amore 	do {
1993*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_t *next;
1994*49ef7e06SGarrett D'Amore 
1995*49ef7e06SGarrett D'Amore 		next = stpp->stp_next;
1996*49ef7e06SGarrett D'Amore 
1997*49ef7e06SGarrett D'Amore 		stpp->stp_next = p;
1998*49ef7e06SGarrett D'Amore 		p = stpp;
1999*49ef7e06SGarrett D'Amore 
2000*49ef7e06SGarrett D'Amore 		count++;
2001*49ef7e06SGarrett D'Amore 		stpp = next;
2002*49ef7e06SGarrett D'Amore 	} while (stpp != NULL);
2003*49ef7e06SGarrett D'Amore 
2004*49ef7e06SGarrett D'Amore 	/* Add it to the tail of the get list */
2005*49ef7e06SGarrett D'Amore 	ASSERT3P(*pp, ==, NULL);
2006*49ef7e06SGarrett D'Amore 
2007*49ef7e06SGarrett D'Amore 	*(stdp->std_getp) = p;
2008*49ef7e06SGarrett D'Amore 	stdp->std_getp = pp;
2009*49ef7e06SGarrett D'Amore 	stdp->std_count += count;
2010*49ef7e06SGarrett D'Amore 	ASSERT3U(stdp->std_count, <=, sfxge_tx_dpl_get_pkt_max(stp));
2011*49ef7e06SGarrett D'Amore 
2012*49ef7e06SGarrett D'Amore 	DTRACE_PROBE2(dpl_counts, int, stdp->std_count, int, count);
2013*49ef7e06SGarrett D'Amore }
2014*49ef7e06SGarrett D'Amore 
2015*49ef7e06SGarrett D'Amore 
2016*49ef7e06SGarrett D'Amore /*
2017*49ef7e06SGarrett D'Amore  * If TXQ locked, add the RX DPL put list and this packet to the TX DPL get list
2018*49ef7e06SGarrett D'Amore  * If TXQ unlocked, atomically add this packet to TX DPL put list
2019*49ef7e06SGarrett D'Amore  *
2020*49ef7e06SGarrett D'Amore  * The only possible error is ENOSPC (used for TX backpressure)
2021*49ef7e06SGarrett D'Amore  * For the TX DPL put or get list becoming full, in both cases there must be
2022*49ef7e06SGarrett D'Amore  * future TX completions (as represented by the packets on the DPL get lists).
2023*49ef7e06SGarrett D'Amore  *
2024*49ef7e06SGarrett D'Amore  * This ensures that in the future mac_tx_update() will be called from
2025*49ef7e06SGarrett D'Amore  * sfxge_tx_qcomplete()
2026*49ef7e06SGarrett D'Amore  */
2027*49ef7e06SGarrett D'Amore static inline int
sfxge_tx_qdpl_add(sfxge_txq_t * stp,sfxge_tx_packet_t * stpp,int locked)2028*49ef7e06SGarrett D'Amore sfxge_tx_qdpl_add(sfxge_txq_t *stp, sfxge_tx_packet_t *stpp, int locked)
2029*49ef7e06SGarrett D'Amore {
2030*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &stp->st_dpl;
2031*49ef7e06SGarrett D'Amore 
2032*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp->stp_next, ==, NULL);
2033*49ef7e06SGarrett D'Amore 
2034*49ef7e06SGarrett D'Amore 	if (locked) {
2035*49ef7e06SGarrett D'Amore 		ASSERT(mutex_owned(&stp->st_lock));
2036*49ef7e06SGarrett D'Amore 
2037*49ef7e06SGarrett D'Amore 		if (stdp->std_count >= stdp->get_pkt_limit) {
2038*49ef7e06SGarrett D'Amore 			stdp->get_full_count++;
2039*49ef7e06SGarrett D'Amore 			return (ENOSPC);
2040*49ef7e06SGarrett D'Amore 		}
2041*49ef7e06SGarrett D'Amore 
2042*49ef7e06SGarrett D'Amore 		/* Reverse the put list onto the get list */
2043*49ef7e06SGarrett D'Amore 		sfxge_tx_qdpl_swizzle(stp);
2044*49ef7e06SGarrett D'Amore 
2045*49ef7e06SGarrett D'Amore 		/* Add to the tail of the get list */
2046*49ef7e06SGarrett D'Amore 		*(stdp->std_getp) = stpp;
2047*49ef7e06SGarrett D'Amore 		stdp->std_getp = &stpp->stp_next;
2048*49ef7e06SGarrett D'Amore 		stdp->std_count++;
2049*49ef7e06SGarrett D'Amore 		ASSERT3U(stdp->std_count, <=, sfxge_tx_dpl_get_pkt_max(stp));
2050*49ef7e06SGarrett D'Amore 
2051*49ef7e06SGarrett D'Amore 	} else {
2052*49ef7e06SGarrett D'Amore 		volatile uintptr_t *putp;
2053*49ef7e06SGarrett D'Amore 		uintptr_t old;
2054*49ef7e06SGarrett D'Amore 		uintptr_t new;
2055*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_t *old_pkt;
2056*49ef7e06SGarrett D'Amore 
2057*49ef7e06SGarrett D'Amore 		putp = &(stdp->std_put);
2058*49ef7e06SGarrett D'Amore 		new = (uintptr_t)stpp;
2059*49ef7e06SGarrett D'Amore 
2060*49ef7e06SGarrett D'Amore 		/* Add to the head of the put list, keeping a list length */
2061*49ef7e06SGarrett D'Amore 		do {
2062*49ef7e06SGarrett D'Amore 			old = *putp;
2063*49ef7e06SGarrett D'Amore 			old_pkt =  (sfxge_tx_packet_t *)old;
2064*49ef7e06SGarrett D'Amore 
2065*49ef7e06SGarrett D'Amore 			stpp->stp_dpl_put_len = old ?
2066*49ef7e06SGarrett D'Amore 			    old_pkt->stp_dpl_put_len + 1 : 1;
2067*49ef7e06SGarrett D'Amore 
2068*49ef7e06SGarrett D'Amore 			if (stpp->stp_dpl_put_len >= stdp->put_pkt_limit) {
2069*49ef7e06SGarrett D'Amore 				stpp->stp_next = 0;
2070*49ef7e06SGarrett D'Amore 				stpp->stp_dpl_put_len = 0;
2071*49ef7e06SGarrett D'Amore 				stdp->put_full_count++;
2072*49ef7e06SGarrett D'Amore 				return (ENOSPC);
2073*49ef7e06SGarrett D'Amore 			}
2074*49ef7e06SGarrett D'Amore 
2075*49ef7e06SGarrett D'Amore 			stpp->stp_next = (void *)old;
2076*49ef7e06SGarrett D'Amore 		} while (atomic_cas_ulong(putp, old, new) != old);
2077*49ef7e06SGarrett D'Amore 	}
2078*49ef7e06SGarrett D'Amore 	return (0);
2079*49ef7e06SGarrett D'Amore }
2080*49ef7e06SGarrett D'Amore 
2081*49ef7e06SGarrett D'Amore 
2082*49ef7e06SGarrett D'Amore /* Take all packets from DPL get list and try to send to HW */
2083*49ef7e06SGarrett D'Amore static void
sfxge_tx_qdpl_drain(sfxge_txq_t * stp)2084*49ef7e06SGarrett D'Amore sfxge_tx_qdpl_drain(sfxge_txq_t *stp)
2085*49ef7e06SGarrett D'Amore {
2086*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
2087*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
2088*49ef7e06SGarrett D'Amore 	unsigned int pushed = stp->st_added;
2089*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
2090*49ef7e06SGarrett D'Amore 	unsigned int count;
2091*49ef7e06SGarrett D'Amore 
2092*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
2093*49ef7e06SGarrett D'Amore 
2094*49ef7e06SGarrett D'Amore 	prefetch_read_many(sp->s_enp);
2095*49ef7e06SGarrett D'Amore 	prefetch_read_many(stp->st_etp);
2096*49ef7e06SGarrett D'Amore 
2097*49ef7e06SGarrett D'Amore 	stpp = stdp->std_get;
2098*49ef7e06SGarrett D'Amore 	count = stdp->std_count;
2099*49ef7e06SGarrett D'Amore 
2100*49ef7e06SGarrett D'Amore 	while (count != 0) {
2101*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_t *next;
2102*49ef7e06SGarrett D'Amore 		boolean_t copy;
2103*49ef7e06SGarrett D'Amore 		int rc;
2104*49ef7e06SGarrett D'Amore 
2105*49ef7e06SGarrett D'Amore 		ASSERT(stpp != NULL);
2106*49ef7e06SGarrett D'Amore 
2107*49ef7e06SGarrett D'Amore 		/* Split stpp off */
2108*49ef7e06SGarrett D'Amore 		next = stpp->stp_next;
2109*49ef7e06SGarrett D'Amore 		stpp->stp_next = NULL;
2110*49ef7e06SGarrett D'Amore 
2111*49ef7e06SGarrett D'Amore 		if (next != NULL)
2112*49ef7e06SGarrett D'Amore 			prefetch_read_many(next);
2113*49ef7e06SGarrett D'Amore 
2114*49ef7e06SGarrett D'Amore 		if (stp->st_state != SFXGE_TXQ_STARTED)
2115*49ef7e06SGarrett D'Amore 			goto reject;
2116*49ef7e06SGarrett D'Amore 
2117*49ef7e06SGarrett D'Amore 		copy = B_FALSE;
2118*49ef7e06SGarrett D'Amore 
2119*49ef7e06SGarrett D'Amore again:
2120*49ef7e06SGarrett D'Amore 		/* Fragment the packet */
2121*49ef7e06SGarrett D'Amore 		if (stpp->stp_mss != 0) {
2122*49ef7e06SGarrett D'Amore 			rc = sfxge_tx_qlso_fragment(stp, stpp, copy);
2123*49ef7e06SGarrett D'Amore 		} else {
2124*49ef7e06SGarrett D'Amore 			rc = sfxge_tx_qpacket_fragment(stp, stpp, copy);
2125*49ef7e06SGarrett D'Amore 		}
2126*49ef7e06SGarrett D'Amore 
2127*49ef7e06SGarrett D'Amore 		switch (rc) {
2128*49ef7e06SGarrett D'Amore 		case 0:
2129*49ef7e06SGarrett D'Amore 			break;
2130*49ef7e06SGarrett D'Amore 
2131*49ef7e06SGarrett D'Amore 		case ENOSPC:
2132*49ef7e06SGarrett D'Amore 			if (!copy)
2133*49ef7e06SGarrett D'Amore 				goto copy;
2134*49ef7e06SGarrett D'Amore 
2135*49ef7e06SGarrett D'Amore 		/*FALLTHRU*/
2136*49ef7e06SGarrett D'Amore 		default:
2137*49ef7e06SGarrett D'Amore 			goto reject;
2138*49ef7e06SGarrett D'Amore 		}
2139*49ef7e06SGarrett D'Amore 
2140*49ef7e06SGarrett D'Amore 		/* Free the packet structure */
2141*49ef7e06SGarrett D'Amore 		stpp->stp_etherhp = NULL;
2142*49ef7e06SGarrett D'Amore 		stpp->stp_iphp = NULL;
2143*49ef7e06SGarrett D'Amore 		stpp->stp_thp = NULL;
2144*49ef7e06SGarrett D'Amore 		stpp->stp_off = 0;
2145*49ef7e06SGarrett D'Amore 		stpp->stp_size = 0;
2146*49ef7e06SGarrett D'Amore 		stpp->stp_mss = 0;
2147*49ef7e06SGarrett D'Amore 		stpp->stp_dpl_put_len = 0;
2148*49ef7e06SGarrett D'Amore 
2149*49ef7e06SGarrett D'Amore 		ASSERT3P(stpp->stp_mp, ==, NULL);
2150*49ef7e06SGarrett D'Amore 
2151*49ef7e06SGarrett D'Amore 		if (sfxge_tx_qfpp_put(stp, stpp) != 0) {
2152*49ef7e06SGarrett D'Amore 			sfxge_tx_packet_destroy(sp, stpp);
2153*49ef7e06SGarrett D'Amore 			stpp = NULL;
2154*49ef7e06SGarrett D'Amore 		}
2155*49ef7e06SGarrett D'Amore 
2156*49ef7e06SGarrett D'Amore 		--count;
2157*49ef7e06SGarrett D'Amore 		stpp = next;
2158*49ef7e06SGarrett D'Amore 
2159*49ef7e06SGarrett D'Amore 		/* Post the packet */
2160*49ef7e06SGarrett D'Amore 		sfxge_tx_qlist_post(stp);
2161*49ef7e06SGarrett D'Amore 
2162*49ef7e06SGarrett D'Amore 		if (stp->st_unblock != SFXGE_TXQ_NOT_BLOCKED)
2163*49ef7e06SGarrett D'Amore 			goto defer;
2164*49ef7e06SGarrett D'Amore 
2165*49ef7e06SGarrett D'Amore 		if (stp->st_added - pushed >= SFXGE_TX_BATCH) {
2166*49ef7e06SGarrett D'Amore 			efx_tx_qpush(stp->st_etp, stp->st_added, pushed);
2167*49ef7e06SGarrett D'Amore 			pushed = stp->st_added;
2168*49ef7e06SGarrett D'Amore 		}
2169*49ef7e06SGarrett D'Amore 
2170*49ef7e06SGarrett D'Amore 		continue;
2171*49ef7e06SGarrett D'Amore 
2172*49ef7e06SGarrett D'Amore copy:
2173*49ef7e06SGarrett D'Amore 		/* Abort the current fragment list */
2174*49ef7e06SGarrett D'Amore 		sfxge_tx_qlist_abort(stp);
2175*49ef7e06SGarrett D'Amore 
2176*49ef7e06SGarrett D'Amore 		/* Try copying the packet to flatten it */
2177*49ef7e06SGarrett D'Amore 		ASSERT(!copy);
2178*49ef7e06SGarrett D'Amore 		copy = B_TRUE;
2179*49ef7e06SGarrett D'Amore 
2180*49ef7e06SGarrett D'Amore 		goto again;
2181*49ef7e06SGarrett D'Amore 
2182*49ef7e06SGarrett D'Amore reject:
2183*49ef7e06SGarrett D'Amore 		/* Abort the current fragment list */
2184*49ef7e06SGarrett D'Amore 		sfxge_tx_qlist_abort(stp);
2185*49ef7e06SGarrett D'Amore 
2186*49ef7e06SGarrett D'Amore 		/* Discard the packet */
2187*49ef7e06SGarrett D'Amore 		freemsg(stpp->stp_mp);
2188*49ef7e06SGarrett D'Amore 		stpp->stp_mp = NULL;
2189*49ef7e06SGarrett D'Amore 
2190*49ef7e06SGarrett D'Amore 		/* Free the packet structure */
2191*49ef7e06SGarrett D'Amore 		stpp->stp_etherhp = NULL;
2192*49ef7e06SGarrett D'Amore 		stpp->stp_iphp = NULL;
2193*49ef7e06SGarrett D'Amore 		stpp->stp_thp = NULL;
2194*49ef7e06SGarrett D'Amore 		stpp->stp_off = 0;
2195*49ef7e06SGarrett D'Amore 		stpp->stp_size = 0;
2196*49ef7e06SGarrett D'Amore 		stpp->stp_mss = 0;
2197*49ef7e06SGarrett D'Amore 		stpp->stp_dpl_put_len = 0;
2198*49ef7e06SGarrett D'Amore 
2199*49ef7e06SGarrett D'Amore 		if (sfxge_tx_qfpp_put(stp, stpp) != 0) {
2200*49ef7e06SGarrett D'Amore 			sfxge_tx_packet_destroy(sp, stpp);
2201*49ef7e06SGarrett D'Amore 			stpp = NULL;
2202*49ef7e06SGarrett D'Amore 		}
2203*49ef7e06SGarrett D'Amore 
2204*49ef7e06SGarrett D'Amore 		--count;
2205*49ef7e06SGarrett D'Amore 		stpp = next;
2206*49ef7e06SGarrett D'Amore 		continue;
2207*49ef7e06SGarrett D'Amore defer:
2208*49ef7e06SGarrett D'Amore 		DTRACE_PROBE1(defer, unsigned int, stp->st_index);
2209*49ef7e06SGarrett D'Amore 		break;
2210*49ef7e06SGarrett D'Amore 	}
2211*49ef7e06SGarrett D'Amore 
2212*49ef7e06SGarrett D'Amore 	if (count == 0) {
2213*49ef7e06SGarrett D'Amore 		/* New empty get list */
2214*49ef7e06SGarrett D'Amore 		ASSERT3P(stpp, ==, NULL);
2215*49ef7e06SGarrett D'Amore 		stdp->std_get = NULL;
2216*49ef7e06SGarrett D'Amore 		stdp->std_count = 0;
2217*49ef7e06SGarrett D'Amore 
2218*49ef7e06SGarrett D'Amore 		stdp->std_getp = &(stdp->std_get);
2219*49ef7e06SGarrett D'Amore 	} else {
2220*49ef7e06SGarrett D'Amore 		/* shorten the list by moving the head */
2221*49ef7e06SGarrett D'Amore 		stdp->std_get = stpp;
2222*49ef7e06SGarrett D'Amore 		stdp->std_count = count;
2223*49ef7e06SGarrett D'Amore 		ASSERT3U(stdp->std_count, <=, sfxge_tx_dpl_get_pkt_max(stp));
2224*49ef7e06SGarrett D'Amore 	}
2225*49ef7e06SGarrett D'Amore 
2226*49ef7e06SGarrett D'Amore 	if (stp->st_added != pushed)
2227*49ef7e06SGarrett D'Amore 		efx_tx_qpush(stp->st_etp, stp->st_added, pushed);
2228*49ef7e06SGarrett D'Amore 
2229*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_unblock != SFXGE_TXQ_NOT_BLOCKED ||
2230*49ef7e06SGarrett D'Amore 	    stdp->std_count == 0);
2231*49ef7e06SGarrett D'Amore }
2232*49ef7e06SGarrett D'Amore 
2233*49ef7e06SGarrett D'Amore /* Swizzle deferred packet list, try and push to HW */
2234*49ef7e06SGarrett D'Amore static inline void
sfxge_tx_qdpl_service(sfxge_txq_t * stp)2235*49ef7e06SGarrett D'Amore sfxge_tx_qdpl_service(sfxge_txq_t *stp)
2236*49ef7e06SGarrett D'Amore {
2237*49ef7e06SGarrett D'Amore 	do {
2238*49ef7e06SGarrett D'Amore 		ASSERT(mutex_owned(&(stp->st_lock)));
2239*49ef7e06SGarrett D'Amore 
2240*49ef7e06SGarrett D'Amore 		if (SFXGE_TX_QDPL_PUT_PENDING(stp))
2241*49ef7e06SGarrett D'Amore 			sfxge_tx_qdpl_swizzle(stp);
2242*49ef7e06SGarrett D'Amore 
2243*49ef7e06SGarrett D'Amore 		if (stp->st_unblock == SFXGE_TXQ_NOT_BLOCKED)
2244*49ef7e06SGarrett D'Amore 			sfxge_tx_qdpl_drain(stp);
2245*49ef7e06SGarrett D'Amore 
2246*49ef7e06SGarrett D'Amore 		mutex_exit(&(stp->st_lock));
2247*49ef7e06SGarrett D'Amore 
2248*49ef7e06SGarrett D'Amore 		if (!SFXGE_TX_QDPL_PUT_PENDING(stp))
2249*49ef7e06SGarrett D'Amore 			break;
2250*49ef7e06SGarrett D'Amore 	} while (mutex_tryenter(&(stp->st_lock)));
2251*49ef7e06SGarrett D'Amore }
2252*49ef7e06SGarrett D'Amore 
2253*49ef7e06SGarrett D'Amore static void
sfxge_tx_qdpl_flush_locked(sfxge_txq_t * stp)2254*49ef7e06SGarrett D'Amore sfxge_tx_qdpl_flush_locked(sfxge_txq_t *stp)
2255*49ef7e06SGarrett D'Amore {
2256*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
2257*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
2258*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
2259*49ef7e06SGarrett D'Amore 	unsigned int count;
2260*49ef7e06SGarrett D'Amore 
2261*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(stp->st_lock)));
2262*49ef7e06SGarrett D'Amore 
2263*49ef7e06SGarrett D'Amore 	/* Swizzle put list to the get list */
2264*49ef7e06SGarrett D'Amore 	sfxge_tx_qdpl_swizzle(stp);
2265*49ef7e06SGarrett D'Amore 
2266*49ef7e06SGarrett D'Amore 	stpp = stdp->std_get;
2267*49ef7e06SGarrett D'Amore 	count = stdp->std_count;
2268*49ef7e06SGarrett D'Amore 
2269*49ef7e06SGarrett D'Amore 	while (count != 0) {
2270*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_t *next;
2271*49ef7e06SGarrett D'Amore 
2272*49ef7e06SGarrett D'Amore 		next = stpp->stp_next;
2273*49ef7e06SGarrett D'Amore 		stpp->stp_next = NULL;
2274*49ef7e06SGarrett D'Amore 
2275*49ef7e06SGarrett D'Amore 		/* Discard the packet */
2276*49ef7e06SGarrett D'Amore 		freemsg(stpp->stp_mp);
2277*49ef7e06SGarrett D'Amore 		stpp->stp_mp = NULL;
2278*49ef7e06SGarrett D'Amore 
2279*49ef7e06SGarrett D'Amore 		/* Free the packet structure */
2280*49ef7e06SGarrett D'Amore 		stpp->stp_etherhp = NULL;
2281*49ef7e06SGarrett D'Amore 		stpp->stp_iphp = NULL;
2282*49ef7e06SGarrett D'Amore 		stpp->stp_thp = NULL;
2283*49ef7e06SGarrett D'Amore 		stpp->stp_off = 0;
2284*49ef7e06SGarrett D'Amore 		stpp->stp_size = 0;
2285*49ef7e06SGarrett D'Amore 		stpp->stp_mss = 0;
2286*49ef7e06SGarrett D'Amore 		stpp->stp_dpl_put_len = 0;
2287*49ef7e06SGarrett D'Amore 
2288*49ef7e06SGarrett D'Amore 		sfxge_tx_packet_destroy(sp, stpp);
2289*49ef7e06SGarrett D'Amore 
2290*49ef7e06SGarrett D'Amore 		--count;
2291*49ef7e06SGarrett D'Amore 		stpp = next;
2292*49ef7e06SGarrett D'Amore 	}
2293*49ef7e06SGarrett D'Amore 
2294*49ef7e06SGarrett D'Amore 	ASSERT3P(stpp, ==, NULL);
2295*49ef7e06SGarrett D'Amore 
2296*49ef7e06SGarrett D'Amore 	/* Empty list */
2297*49ef7e06SGarrett D'Amore 	stdp->std_get = NULL;
2298*49ef7e06SGarrett D'Amore 	stdp->std_count = 0;
2299*49ef7e06SGarrett D'Amore 	stdp->std_getp = &(stdp->std_get);
2300*49ef7e06SGarrett D'Amore }
2301*49ef7e06SGarrett D'Amore 
2302*49ef7e06SGarrett D'Amore 
2303*49ef7e06SGarrett D'Amore void
sfxge_tx_qdpl_flush(sfxge_txq_t * stp)2304*49ef7e06SGarrett D'Amore sfxge_tx_qdpl_flush(sfxge_txq_t *stp)
2305*49ef7e06SGarrett D'Amore {
2306*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
2307*49ef7e06SGarrett D'Amore 	sfxge_tx_qdpl_flush_locked(stp);
2308*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
2309*49ef7e06SGarrett D'Amore }
2310*49ef7e06SGarrett D'Amore 
2311*49ef7e06SGarrett D'Amore 
2312*49ef7e06SGarrett D'Amore static void
sfxge_tx_qunblock(sfxge_txq_t * stp)2313*49ef7e06SGarrett D'Amore sfxge_tx_qunblock(sfxge_txq_t *stp)
2314*49ef7e06SGarrett D'Amore {
2315*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
2316*49ef7e06SGarrett D'Amore 	unsigned int evq = stp->st_evq;
2317*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[evq];
2318*49ef7e06SGarrett D'Amore 
2319*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
2320*49ef7e06SGarrett D'Amore 
2321*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
2322*49ef7e06SGarrett D'Amore 
2323*49ef7e06SGarrett D'Amore 	if (stp->st_state != SFXGE_TXQ_STARTED) {
2324*49ef7e06SGarrett D'Amore 		mutex_exit(&(stp->st_lock));
2325*49ef7e06SGarrett D'Amore 		return;
2326*49ef7e06SGarrett D'Amore 	}
2327*49ef7e06SGarrett D'Amore 
2328*49ef7e06SGarrett D'Amore 	if (stp->st_unblock != SFXGE_TXQ_NOT_BLOCKED) {
2329*49ef7e06SGarrett D'Amore 		unsigned int level;
2330*49ef7e06SGarrett D'Amore 
2331*49ef7e06SGarrett D'Amore 		level = stp->st_added - stp->st_completed;
2332*49ef7e06SGarrett D'Amore 		if (level <= stp->st_unblock) {
2333*49ef7e06SGarrett D'Amore 			stp->st_unblock = SFXGE_TXQ_NOT_BLOCKED;
2334*49ef7e06SGarrett D'Amore 			sfxge_tx_qlist_post(stp);
2335*49ef7e06SGarrett D'Amore 		}
2336*49ef7e06SGarrett D'Amore 	}
2337*49ef7e06SGarrett D'Amore 
2338*49ef7e06SGarrett D'Amore 	sfxge_tx_qdpl_service(stp);
2339*49ef7e06SGarrett D'Amore 	/* lock has been dropped */
2340*49ef7e06SGarrett D'Amore }
2341*49ef7e06SGarrett D'Amore 
2342*49ef7e06SGarrett D'Amore void
sfxge_tx_qcomplete(sfxge_txq_t * stp)2343*49ef7e06SGarrett D'Amore sfxge_tx_qcomplete(sfxge_txq_t *stp)
2344*49ef7e06SGarrett D'Amore {
2345*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
2346*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
2347*49ef7e06SGarrett D'Amore 	unsigned int evq = stp->st_evq;
2348*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[evq];
2349*49ef7e06SGarrett D'Amore 	unsigned int completed;
2350*49ef7e06SGarrett D'Amore 
2351*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
2352*49ef7e06SGarrett D'Amore 
2353*49ef7e06SGarrett D'Amore 	completed = stp->st_completed;
2354*49ef7e06SGarrett D'Amore 	while (completed != stp->st_pending) {
2355*49ef7e06SGarrett D'Amore 		unsigned int id;
2356*49ef7e06SGarrett D'Amore 		sfxge_tx_mapping_t *stmp;
2357*49ef7e06SGarrett D'Amore 
2358*49ef7e06SGarrett D'Amore 		id = completed++ & (SFXGE_TX_NDESCS - 1);
2359*49ef7e06SGarrett D'Amore 
2360*49ef7e06SGarrett D'Amore 		if ((stmp = stp->st_stmp[id]) != NULL) {
2361*49ef7e06SGarrett D'Amore 			mblk_t *mp;
2362*49ef7e06SGarrett D'Amore 
2363*49ef7e06SGarrett D'Amore 			/* Unbind all the mappings */
2364*49ef7e06SGarrett D'Amore 			do {
2365*49ef7e06SGarrett D'Amore 				ASSERT(stmp->stm_mp != NULL);
2366*49ef7e06SGarrett D'Amore 				sfxge_tx_msgb_unbind(stmp);
2367*49ef7e06SGarrett D'Amore 
2368*49ef7e06SGarrett D'Amore 				stmp = stmp->stm_next;
2369*49ef7e06SGarrett D'Amore 			} while (stmp != NULL);
2370*49ef7e06SGarrett D'Amore 
2371*49ef7e06SGarrett D'Amore 			/*
2372*49ef7e06SGarrett D'Amore 			 * Now that the packet is no longer mapped for DMA it
2373*49ef7e06SGarrett D'Amore 			 * can be freed.
2374*49ef7e06SGarrett D'Amore 			 */
2375*49ef7e06SGarrett D'Amore 			mp = stp->st_mp[id];
2376*49ef7e06SGarrett D'Amore 			stp->st_mp[id] = NULL;
2377*49ef7e06SGarrett D'Amore 
2378*49ef7e06SGarrett D'Amore 			ASSERT(mp != NULL);
2379*49ef7e06SGarrett D'Amore 			freemsg(mp);
2380*49ef7e06SGarrett D'Amore 		}
2381*49ef7e06SGarrett D'Amore 	}
2382*49ef7e06SGarrett D'Amore 	stp->st_completed = completed;
2383*49ef7e06SGarrett D'Amore 
2384*49ef7e06SGarrett D'Amore 	/* Check whether we need to unblock the queue */
2385*49ef7e06SGarrett D'Amore 	if (stp->st_unblock != SFXGE_TXQ_NOT_BLOCKED) {
2386*49ef7e06SGarrett D'Amore 		unsigned int level;
2387*49ef7e06SGarrett D'Amore 
2388*49ef7e06SGarrett D'Amore 		level = stp->st_added - stp->st_completed;
2389*49ef7e06SGarrett D'Amore 		if (level <= stp->st_unblock)
2390*49ef7e06SGarrett D'Amore 			sfxge_tx_qunblock(stp);
2391*49ef7e06SGarrett D'Amore 	}
2392*49ef7e06SGarrett D'Amore 
2393*49ef7e06SGarrett D'Amore 	/* Release TX backpressure from the TX DPL put/get list being full */
2394*49ef7e06SGarrett D'Amore 	if (stdp->std_count < stdp->get_pkt_limit)
2395*49ef7e06SGarrett D'Amore 		mac_tx_update(sp->s_mh);
2396*49ef7e06SGarrett D'Amore }
2397*49ef7e06SGarrett D'Amore 
2398*49ef7e06SGarrett D'Amore void
sfxge_tx_qflush_done(sfxge_txq_t * stp)2399*49ef7e06SGarrett D'Amore sfxge_tx_qflush_done(sfxge_txq_t *stp)
2400*49ef7e06SGarrett D'Amore {
2401*49ef7e06SGarrett D'Amore 	sfxge_t *sp = stp->st_sp;
2402*49ef7e06SGarrett D'Amore 	boolean_t flush_pending = B_FALSE;
2403*49ef7e06SGarrett D'Amore 
2404*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sp->s_sep[stp->st_evq]->se_lock)));
2405*49ef7e06SGarrett D'Amore 
2406*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
2407*49ef7e06SGarrett D'Amore 
2408*49ef7e06SGarrett D'Amore 	switch (stp->st_state) {
2409*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_INITIALIZED:
2410*49ef7e06SGarrett D'Amore 		/* Ignore flush event after TxQ destroyed */
2411*49ef7e06SGarrett D'Amore 		break;
2412*49ef7e06SGarrett D'Amore 
2413*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_FLUSH_PENDING:
2414*49ef7e06SGarrett D'Amore 		flush_pending = B_TRUE;
2415*49ef7e06SGarrett D'Amore 		stp->st_state = SFXGE_TXQ_FLUSH_DONE;
2416*49ef7e06SGarrett D'Amore 		break;
2417*49ef7e06SGarrett D'Amore 
2418*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_FLUSH_FAILED:
2419*49ef7e06SGarrett D'Amore 		/* MC may have rebooted before handling the flush request */
2420*49ef7e06SGarrett D'Amore 		stp->st_state = SFXGE_TXQ_FLUSH_DONE;
2421*49ef7e06SGarrett D'Amore 		break;
2422*49ef7e06SGarrett D'Amore 
2423*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_STARTED:
2424*49ef7e06SGarrett D'Amore 		/*
2425*49ef7e06SGarrett D'Amore 		 * MC initiated flush on MC reboot or because of bad Tx
2426*49ef7e06SGarrett D'Amore 		 * descriptor
2427*49ef7e06SGarrett D'Amore 		 */
2428*49ef7e06SGarrett D'Amore 		stp->st_state = SFXGE_TXQ_FLUSH_DONE;
2429*49ef7e06SGarrett D'Amore 		break;
2430*49ef7e06SGarrett D'Amore 
2431*49ef7e06SGarrett D'Amore 	case SFXGE_TXQ_FLUSH_DONE:
2432*49ef7e06SGarrett D'Amore 		/* Ignore unexpected extra flush event */
2433*49ef7e06SGarrett D'Amore 		ASSERT(B_FALSE);
2434*49ef7e06SGarrett D'Amore 		break;
2435*49ef7e06SGarrett D'Amore 
2436*49ef7e06SGarrett D'Amore 	default:
2437*49ef7e06SGarrett D'Amore 		ASSERT(B_FALSE);
2438*49ef7e06SGarrett D'Amore 	}
2439*49ef7e06SGarrett D'Amore 
2440*49ef7e06SGarrett D'Amore 
2441*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
2442*49ef7e06SGarrett D'Amore 
2443*49ef7e06SGarrett D'Amore 	if (flush_pending == B_FALSE) {
2444*49ef7e06SGarrett D'Amore 		/* Flush was not pending */
2445*49ef7e06SGarrett D'Amore 		return;
2446*49ef7e06SGarrett D'Amore 	}
2447*49ef7e06SGarrett D'Amore 
2448*49ef7e06SGarrett D'Amore 	mutex_enter(&(sp->s_tx_flush_lock));
2449*49ef7e06SGarrett D'Amore 	sp->s_tx_flush_pending--;
2450*49ef7e06SGarrett D'Amore 	if (sp->s_tx_flush_pending <= 0) {
2451*49ef7e06SGarrett D'Amore 		/* All queues flushed: wakeup sfxge_tx_stop() */
2452*49ef7e06SGarrett D'Amore 		cv_signal(&(sp->s_tx_flush_kv));
2453*49ef7e06SGarrett D'Amore 	}
2454*49ef7e06SGarrett D'Amore 	mutex_exit(&(sp->s_tx_flush_lock));
2455*49ef7e06SGarrett D'Amore }
2456*49ef7e06SGarrett D'Amore 
2457*49ef7e06SGarrett D'Amore static void
sfxge_tx_qflush(sfxge_t * sp,unsigned int index,boolean_t wait_for_flush)2458*49ef7e06SGarrett D'Amore sfxge_tx_qflush(sfxge_t *sp, unsigned int index, boolean_t wait_for_flush)
2459*49ef7e06SGarrett D'Amore {
2460*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = sp->s_stp[index];
2461*49ef7e06SGarrett D'Amore 	int rc;
2462*49ef7e06SGarrett D'Amore 
2463*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sp->s_state_lock)));
2464*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sp->s_tx_flush_lock)));
2465*49ef7e06SGarrett D'Amore 
2466*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
2467*49ef7e06SGarrett D'Amore 
2468*49ef7e06SGarrett D'Amore 	/* Prepare to flush and stop the queue */
2469*49ef7e06SGarrett D'Amore 	if (stp->st_state == SFXGE_TXQ_STARTED) {
2470*49ef7e06SGarrett D'Amore 		/* Flush the transmit queue */
2471*49ef7e06SGarrett D'Amore 		if ((rc = efx_tx_qflush(stp->st_etp)) == EALREADY) {
2472*49ef7e06SGarrett D'Amore 			/* Already flushed, may be initiated by MC */
2473*49ef7e06SGarrett D'Amore 			stp->st_state = SFXGE_TXQ_FLUSH_DONE;
2474*49ef7e06SGarrett D'Amore 		} else if (rc != 0) {
2475*49ef7e06SGarrett D'Amore 			/* Unexpected error */
2476*49ef7e06SGarrett D'Amore 			stp->st_state = SFXGE_TXQ_FLUSH_FAILED;
2477*49ef7e06SGarrett D'Amore 		} else if (wait_for_flush) {
2478*49ef7e06SGarrett D'Amore 			stp->st_state = SFXGE_TXQ_FLUSH_PENDING;
2479*49ef7e06SGarrett D'Amore 			sp->s_tx_flush_pending++;
2480*49ef7e06SGarrett D'Amore 		} else {
2481*49ef7e06SGarrett D'Amore 			/* Assume the flush is done */
2482*49ef7e06SGarrett D'Amore 			stp->st_state = SFXGE_TXQ_FLUSH_DONE;
2483*49ef7e06SGarrett D'Amore 		}
2484*49ef7e06SGarrett D'Amore 	}
2485*49ef7e06SGarrett D'Amore 
2486*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
2487*49ef7e06SGarrett D'Amore }
2488*49ef7e06SGarrett D'Amore 
2489*49ef7e06SGarrett D'Amore static void
sfxge_tx_qstop(sfxge_t * sp,unsigned int index)2490*49ef7e06SGarrett D'Amore sfxge_tx_qstop(sfxge_t *sp, unsigned int index)
2491*49ef7e06SGarrett D'Amore {
2492*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = sp->s_stp[index];
2493*49ef7e06SGarrett D'Amore 	unsigned int evq = stp->st_evq;
2494*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[evq];
2495*49ef7e06SGarrett D'Amore 
2496*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
2497*49ef7e06SGarrett D'Amore 	mutex_enter(&(stp->st_lock));
2498*49ef7e06SGarrett D'Amore 
2499*49ef7e06SGarrett D'Amore 	if (stp->st_state == SFXGE_TXQ_INITIALIZED)
2500*49ef7e06SGarrett D'Amore 		goto done;
2501*49ef7e06SGarrett D'Amore 
2502*49ef7e06SGarrett D'Amore 	ASSERT(stp->st_state == SFXGE_TXQ_FLUSH_PENDING ||
2503*49ef7e06SGarrett D'Amore 	    stp->st_state == SFXGE_TXQ_FLUSH_DONE ||
2504*49ef7e06SGarrett D'Amore 	    stp->st_state == SFXGE_TXQ_FLUSH_FAILED);
2505*49ef7e06SGarrett D'Amore 
2506*49ef7e06SGarrett D'Amore 	/* All queues should have been flushed */
2507*49ef7e06SGarrett D'Amore 	if (stp->st_sp->s_tx_flush_pending != 0) {
2508*49ef7e06SGarrett D'Amore 		dev_err(sp->s_dip, CE_NOTE,
2509*49ef7e06SGarrett D'Amore 		    SFXGE_CMN_ERR "txq[%d] stop with flush_pending=%d",
2510*49ef7e06SGarrett D'Amore 		    index, stp->st_sp->s_tx_flush_pending);
2511*49ef7e06SGarrett D'Amore 	}
2512*49ef7e06SGarrett D'Amore 	if (stp->st_state == SFXGE_TXQ_FLUSH_FAILED) {
2513*49ef7e06SGarrett D'Amore 		dev_err(sp->s_dip, CE_NOTE,
2514*49ef7e06SGarrett D'Amore 		    SFXGE_CMN_ERR "txq[%d] flush failed", index);
2515*49ef7e06SGarrett D'Amore 	}
2516*49ef7e06SGarrett D'Amore 
2517*49ef7e06SGarrett D'Amore 	/* Destroy the transmit queue */
2518*49ef7e06SGarrett D'Amore 	efx_tx_qdestroy(stp->st_etp);
2519*49ef7e06SGarrett D'Amore 	stp->st_etp = NULL;
2520*49ef7e06SGarrett D'Amore 
2521*49ef7e06SGarrett D'Amore 	/* Clear entries from the buffer table */
2522*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_clear(sp, stp->st_id,
2523*49ef7e06SGarrett D'Amore 	    EFX_TXQ_NBUFS(SFXGE_TX_NDESCS));
2524*49ef7e06SGarrett D'Amore 
2525*49ef7e06SGarrett D'Amore 	sfxge_tx_qlist_abort(stp);
2526*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_n, ==, 0);
2527*49ef7e06SGarrett D'Amore 
2528*49ef7e06SGarrett D'Amore 	stp->st_unblock = SFXGE_TXQ_NOT_BLOCKED;
2529*49ef7e06SGarrett D'Amore 
2530*49ef7e06SGarrett D'Amore 	stp->st_pending = stp->st_added;
2531*49ef7e06SGarrett D'Amore 
2532*49ef7e06SGarrett D'Amore 	sfxge_tx_qcomplete(stp);
2533*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_completed, ==, stp->st_pending);
2534*49ef7e06SGarrett D'Amore 
2535*49ef7e06SGarrett D'Amore 	sfxge_tx_qreap(stp);
2536*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_reaped, ==, stp->st_completed);
2537*49ef7e06SGarrett D'Amore 
2538*49ef7e06SGarrett D'Amore 	/*
2539*49ef7e06SGarrett D'Amore 	 * Ensure the deferred packet list is cleared
2540*49ef7e06SGarrett D'Amore 	 * Can race with sfxge_tx_packet_add() adding to the put list
2541*49ef7e06SGarrett D'Amore 	 */
2542*49ef7e06SGarrett D'Amore 	sfxge_tx_qdpl_flush_locked(stp);
2543*49ef7e06SGarrett D'Amore 
2544*49ef7e06SGarrett D'Amore 	stp->st_added = 0;
2545*49ef7e06SGarrett D'Amore 	stp->st_pending = 0;
2546*49ef7e06SGarrett D'Amore 	stp->st_completed = 0;
2547*49ef7e06SGarrett D'Amore 	stp->st_reaped = 0;
2548*49ef7e06SGarrett D'Amore 
2549*49ef7e06SGarrett D'Amore 	stp->st_state = SFXGE_TXQ_INITIALIZED;
2550*49ef7e06SGarrett D'Amore 
2551*49ef7e06SGarrett D'Amore done:
2552*49ef7e06SGarrett D'Amore 	mutex_exit(&(stp->st_lock));
2553*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
2554*49ef7e06SGarrett D'Amore }
2555*49ef7e06SGarrett D'Amore 
2556*49ef7e06SGarrett D'Amore static void
sfxge_tx_qfini(sfxge_t * sp,unsigned int index)2557*49ef7e06SGarrett D'Amore sfxge_tx_qfini(sfxge_t *sp, unsigned int index)
2558*49ef7e06SGarrett D'Amore {
2559*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp = sp->s_stp[index];
2560*49ef7e06SGarrett D'Amore 	sfxge_tx_dpl_t *stdp = &(stp->st_dpl);
2561*49ef7e06SGarrett D'Amore 
2562*49ef7e06SGarrett D'Amore 	ASSERT3U(stp->st_state, ==, SFXGE_TXQ_INITIALIZED);
2563*49ef7e06SGarrett D'Amore 	stp->st_state = SFXGE_TXQ_UNINITIALIZED;
2564*49ef7e06SGarrett D'Amore 
2565*49ef7e06SGarrett D'Amore 	/* Detach the TXQ from the driver */
2566*49ef7e06SGarrett D'Amore 	sp->s_stp[index] = NULL;
2567*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_tx_qcount > 0);
2568*49ef7e06SGarrett D'Amore 	sp->s_tx_qcount--;
2569*49ef7e06SGarrett D'Amore 
2570*49ef7e06SGarrett D'Amore 	/* Free the EVQ label for events from this TXQ */
2571*49ef7e06SGarrett D'Amore 	(void) sfxge_ev_txlabel_free(sp, stp->st_evq, stp, stp->st_label);
2572*49ef7e06SGarrett D'Amore 	stp->st_label = 0;
2573*49ef7e06SGarrett D'Amore 
2574*49ef7e06SGarrett D'Amore 	/* Tear down the statistics */
2575*49ef7e06SGarrett D'Amore 	sfxge_tx_kstat_fini(stp);
2576*49ef7e06SGarrett D'Amore 
2577*49ef7e06SGarrett D'Amore 	/* Ensure the deferred packet list is empty */
2578*49ef7e06SGarrett D'Amore 	ASSERT3U(stdp->std_count, ==, 0);
2579*49ef7e06SGarrett D'Amore 	ASSERT3P(stdp->std_get, ==, NULL);
2580*49ef7e06SGarrett D'Amore 	ASSERT3U(stdp->std_put, ==, 0);
2581*49ef7e06SGarrett D'Amore 
2582*49ef7e06SGarrett D'Amore 	/* Clear the free buffer pool */
2583*49ef7e06SGarrett D'Amore 	sfxge_tx_qfbp_empty(stp);
2584*49ef7e06SGarrett D'Amore 
2585*49ef7e06SGarrett D'Amore 	/* Clear the free mapping pool */
2586*49ef7e06SGarrett D'Amore 	sfxge_tx_qfmp_empty(stp);
2587*49ef7e06SGarrett D'Amore 
2588*49ef7e06SGarrett D'Amore 	/* Clear the free packet pool */
2589*49ef7e06SGarrett D'Amore 	sfxge_tx_qfpp_empty(stp);
2590*49ef7e06SGarrett D'Amore 
2591*49ef7e06SGarrett D'Amore 	mutex_destroy(&(stp->st_lock));
2592*49ef7e06SGarrett D'Amore 
2593*49ef7e06SGarrett D'Amore 	stp->st_evq = 0;
2594*49ef7e06SGarrett D'Amore 	stp->st_type = 0;
2595*49ef7e06SGarrett D'Amore 	stp->st_index = 0;
2596*49ef7e06SGarrett D'Amore 
2597*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_tqc, stp);
2598*49ef7e06SGarrett D'Amore }
2599*49ef7e06SGarrett D'Amore 
2600*49ef7e06SGarrett D'Amore int
sfxge_tx_init(sfxge_t * sp)2601*49ef7e06SGarrett D'Amore sfxge_tx_init(sfxge_t *sp)
2602*49ef7e06SGarrett D'Amore {
2603*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2604*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
2605*49ef7e06SGarrett D'Amore 	sfxge_txq_type_t qtype;
2606*49ef7e06SGarrett D'Amore 	unsigned int txq, evq;
2607*49ef7e06SGarrett D'Amore 	int index;
2608*49ef7e06SGarrett D'Amore 	int rc;
2609*49ef7e06SGarrett D'Amore 
2610*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_tx_packet_cache",
2611*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
2612*49ef7e06SGarrett D'Amore 
2613*49ef7e06SGarrett D'Amore 	sp->s_tpc = kmem_cache_create(name, sizeof (sfxge_tx_packet_t),
2614*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, sfxge_tx_packet_ctor, sfxge_tx_packet_dtor,
2615*49ef7e06SGarrett D'Amore 	    NULL, sp, NULL, 0);
2616*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_tpc != NULL);
2617*49ef7e06SGarrett D'Amore 
2618*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_tx_buffer_cache",
2619*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
2620*49ef7e06SGarrett D'Amore 
2621*49ef7e06SGarrett D'Amore 	sp->s_tbc = kmem_cache_create(name, sizeof (sfxge_tx_buffer_t),
2622*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, sfxge_tx_buffer_ctor, sfxge_tx_buffer_dtor,
2623*49ef7e06SGarrett D'Amore 	    NULL, sp, NULL, 0);
2624*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_tbc != NULL);
2625*49ef7e06SGarrett D'Amore 
2626*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_tx_mapping_cache",
2627*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
2628*49ef7e06SGarrett D'Amore 
2629*49ef7e06SGarrett D'Amore 	sp->s_tmc = kmem_cache_create(name, sizeof (sfxge_tx_mapping_t),
2630*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, sfxge_tx_mapping_ctor, sfxge_tx_mapping_dtor,
2631*49ef7e06SGarrett D'Amore 	    NULL, sp, NULL, 0);
2632*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_tmc != NULL);
2633*49ef7e06SGarrett D'Amore 
2634*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_txq_cache",
2635*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
2636*49ef7e06SGarrett D'Amore 
2637*49ef7e06SGarrett D'Amore 	sp->s_tqc = kmem_cache_create(name, sizeof (sfxge_txq_t),
2638*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, sfxge_tx_qctor, sfxge_tx_qdtor, NULL, sp,
2639*49ef7e06SGarrett D'Amore 	    NULL, 0);
2640*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_tqc != NULL);
2641*49ef7e06SGarrett D'Amore 
2642*49ef7e06SGarrett D'Amore 	/* Initialize the transmit queues. */
2643*49ef7e06SGarrett D'Amore 	sp->s_tx_scale_max[SFXGE_TXQ_NON_CKSUM]		= sip->si_nalloc;
2644*49ef7e06SGarrett D'Amore 	sp->s_tx_scale_max[SFXGE_TXQ_IP_CKSUM]		= 1;
2645*49ef7e06SGarrett D'Amore 	sp->s_tx_scale_max[SFXGE_TXQ_IP_TCP_UDP_CKSUM]	= sip->si_nalloc;
2646*49ef7e06SGarrett D'Amore 
2647*49ef7e06SGarrett D'Amore 	/* Ensure minimum queue counts required by sfxge_tx_packet_add(). */
2648*49ef7e06SGarrett D'Amore 	if (sp->s_tx_scale_max[SFXGE_TXQ_NON_CKSUM] < 1)
2649*49ef7e06SGarrett D'Amore 		sp->s_tx_scale_max[SFXGE_TXQ_NON_CKSUM] = 1;
2650*49ef7e06SGarrett D'Amore 
2651*49ef7e06SGarrett D'Amore 	if (sp->s_tx_scale_max[SFXGE_TXQ_IP_CKSUM] < 1)
2652*49ef7e06SGarrett D'Amore 		sp->s_tx_scale_max[SFXGE_TXQ_IP_CKSUM] = 1;
2653*49ef7e06SGarrett D'Amore 
2654*49ef7e06SGarrett D'Amore 	txq = 0;
2655*49ef7e06SGarrett D'Amore 	for (qtype = 0; qtype < SFXGE_TXQ_NTYPES; qtype++) {
2656*49ef7e06SGarrett D'Amore 		unsigned int tx_scale = sp->s_tx_scale_max[qtype];
2657*49ef7e06SGarrett D'Amore 
2658*49ef7e06SGarrett D'Amore 		if (txq + tx_scale > EFX_ARRAY_SIZE(sp->s_stp)) {
2659*49ef7e06SGarrett D'Amore 			rc = EINVAL;
2660*49ef7e06SGarrett D'Amore 			goto fail1;
2661*49ef7e06SGarrett D'Amore 		}
2662*49ef7e06SGarrett D'Amore 
2663*49ef7e06SGarrett D'Amore 		sp->s_tx_scale_base[qtype] = txq;
2664*49ef7e06SGarrett D'Amore 
2665*49ef7e06SGarrett D'Amore 		for (evq = 0; evq < tx_scale; evq++) {
2666*49ef7e06SGarrett D'Amore 			if ((rc = sfxge_tx_qinit(sp, txq, qtype, evq)) != 0) {
2667*49ef7e06SGarrett D'Amore 				goto fail2;
2668*49ef7e06SGarrett D'Amore 			}
2669*49ef7e06SGarrett D'Amore 			txq++;
2670*49ef7e06SGarrett D'Amore 		}
2671*49ef7e06SGarrett D'Amore 		ASSERT3U(txq, <=, EFX_ARRAY_SIZE(sp->s_stp));
2672*49ef7e06SGarrett D'Amore 	}
2673*49ef7e06SGarrett D'Amore 
2674*49ef7e06SGarrett D'Amore 	return (0);
2675*49ef7e06SGarrett D'Amore 
2676*49ef7e06SGarrett D'Amore fail2:
2677*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2678*49ef7e06SGarrett D'Amore 
2679*49ef7e06SGarrett D'Amore fail1:
2680*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2681*49ef7e06SGarrett D'Amore 
2682*49ef7e06SGarrett D'Amore 	index = EFX_ARRAY_SIZE(sp->s_stp);
2683*49ef7e06SGarrett D'Amore 	while (--index >= 0) {
2684*49ef7e06SGarrett D'Amore 		if (sp->s_stp[index] != NULL)
2685*49ef7e06SGarrett D'Amore 			sfxge_tx_qfini(sp, index);
2686*49ef7e06SGarrett D'Amore 	}
2687*49ef7e06SGarrett D'Amore 
2688*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tqc);
2689*49ef7e06SGarrett D'Amore 	sp->s_tqc = NULL;
2690*49ef7e06SGarrett D'Amore 
2691*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tmc);
2692*49ef7e06SGarrett D'Amore 	sp->s_tmc = NULL;
2693*49ef7e06SGarrett D'Amore 
2694*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tbc);
2695*49ef7e06SGarrett D'Amore 	sp->s_tbc = NULL;
2696*49ef7e06SGarrett D'Amore 
2697*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tpc);
2698*49ef7e06SGarrett D'Amore 	sp->s_tpc = NULL;
2699*49ef7e06SGarrett D'Amore 
2700*49ef7e06SGarrett D'Amore 	return (rc);
2701*49ef7e06SGarrett D'Amore }
2702*49ef7e06SGarrett D'Amore 
2703*49ef7e06SGarrett D'Amore int
sfxge_tx_start(sfxge_t * sp)2704*49ef7e06SGarrett D'Amore sfxge_tx_start(sfxge_t *sp)
2705*49ef7e06SGarrett D'Amore {
2706*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
2707*49ef7e06SGarrett D'Amore 	int index;
2708*49ef7e06SGarrett D'Amore 	int rc;
2709*49ef7e06SGarrett D'Amore 
2710*49ef7e06SGarrett D'Amore 	/* Initialize the transmit module */
2711*49ef7e06SGarrett D'Amore 	if ((rc = efx_tx_init(enp)) != 0)
2712*49ef7e06SGarrett D'Amore 		goto fail1;
2713*49ef7e06SGarrett D'Amore 
2714*49ef7e06SGarrett D'Amore 	for (index = 0; index < EFX_ARRAY_SIZE(sp->s_stp); index++) {
2715*49ef7e06SGarrett D'Amore 		if (sp->s_stp[index] != NULL)
2716*49ef7e06SGarrett D'Amore 			if ((rc = sfxge_tx_qstart(sp, index)) != 0)
2717*49ef7e06SGarrett D'Amore 				goto fail2;
2718*49ef7e06SGarrett D'Amore 	}
2719*49ef7e06SGarrett D'Amore 
2720*49ef7e06SGarrett D'Amore 	return (0);
2721*49ef7e06SGarrett D'Amore 
2722*49ef7e06SGarrett D'Amore fail2:
2723*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2724*49ef7e06SGarrett D'Amore 
2725*49ef7e06SGarrett D'Amore 	sfxge_tx_stop(sp);
2726*49ef7e06SGarrett D'Amore 
2727*49ef7e06SGarrett D'Amore fail1:
2728*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2729*49ef7e06SGarrett D'Amore 
2730*49ef7e06SGarrett D'Amore 	return (rc);
2731*49ef7e06SGarrett D'Amore }
2732*49ef7e06SGarrett D'Amore 
2733*49ef7e06SGarrett D'Amore 
2734*49ef7e06SGarrett D'Amore /*
2735*49ef7e06SGarrett D'Amore  * Add a packet to the TX Deferred Packet List and if the TX queue lock
2736*49ef7e06SGarrett D'Amore  * can be acquired then call sfxge_tx_qdpl_service() to fragment and push
2737*49ef7e06SGarrett D'Amore  * to the H/W transmit descriptor ring
2738*49ef7e06SGarrett D'Amore  *
2739*49ef7e06SGarrett D'Amore  * If ENOSPC is returned then the DPL is full or the packet create failed, but
2740*49ef7e06SGarrett D'Amore  * the mblk isn't freed so that the caller can return this mblk from mc_tx() to
2741*49ef7e06SGarrett D'Amore  * back-pressure the OS stack.
2742*49ef7e06SGarrett D'Amore  *
2743*49ef7e06SGarrett D'Amore  * For all other errors the mblk is freed
2744*49ef7e06SGarrett D'Amore  */
2745*49ef7e06SGarrett D'Amore int
sfxge_tx_packet_add(sfxge_t * sp,mblk_t * mp)2746*49ef7e06SGarrett D'Amore sfxge_tx_packet_add(sfxge_t *sp, mblk_t *mp)
2747*49ef7e06SGarrett D'Amore {
2748*49ef7e06SGarrett D'Amore 	struct ether_header *etherhp;
2749*49ef7e06SGarrett D'Amore 	struct ip *iphp;
2750*49ef7e06SGarrett D'Amore 	struct tcphdr *thp;
2751*49ef7e06SGarrett D'Amore 	size_t off;
2752*49ef7e06SGarrett D'Amore 	size_t size;
2753*49ef7e06SGarrett D'Amore 	size_t mss;
2754*49ef7e06SGarrett D'Amore 	sfxge_txq_t *stp;
2755*49ef7e06SGarrett D'Amore 	unsigned int txq;
2756*49ef7e06SGarrett D'Amore 	int index;
2757*49ef7e06SGarrett D'Amore 	boolean_t locked;
2758*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_t *stpp;
2759*49ef7e06SGarrett D'Amore 	sfxge_packet_type_t pkt_type;
2760*49ef7e06SGarrett D'Amore 	uint16_t sport, dport;
2761*49ef7e06SGarrett D'Amore 	int rc = 0;
2762*49ef7e06SGarrett D'Amore 
2763*49ef7e06SGarrett D'Amore 	ASSERT3P(mp->b_next, ==, NULL);
2764*49ef7e06SGarrett D'Amore 	ASSERT(!(DB_CKSUMFLAGS(mp) & HCK_PARTIALCKSUM));
2765*49ef7e06SGarrett D'Amore 
2766*49ef7e06SGarrett D'Amore 	/*
2767*49ef7e06SGarrett D'Amore 	 * Do not enqueue packets during startup/shutdown;
2768*49ef7e06SGarrett D'Amore 	 *
2769*49ef7e06SGarrett D'Amore 	 * NOTE: This access to the state is NOT protected by the state lock. It
2770*49ef7e06SGarrett D'Amore 	 * is an imperfect test and anything further getting onto the get/put
2771*49ef7e06SGarrett D'Amore 	 * deferred packet lists is cleaned up in (possibly repeated) calls to
2772*49ef7e06SGarrett D'Amore 	 * sfxge_can_destroy().
2773*49ef7e06SGarrett D'Amore 	 */
2774*49ef7e06SGarrett D'Amore 	if (sp->s_state != SFXGE_STARTED) {
2775*49ef7e06SGarrett D'Amore 		rc = EINVAL;
2776*49ef7e06SGarrett D'Amore 		goto fail1;
2777*49ef7e06SGarrett D'Amore 	}
2778*49ef7e06SGarrett D'Amore 
2779*49ef7e06SGarrett D'Amore 	etherhp = NULL;
2780*49ef7e06SGarrett D'Amore 	iphp = NULL;
2781*49ef7e06SGarrett D'Amore 	thp = NULL;
2782*49ef7e06SGarrett D'Amore 	off = 0;
2783*49ef7e06SGarrett D'Amore 	size = 0;
2784*49ef7e06SGarrett D'Amore 	mss = 0;
2785*49ef7e06SGarrett D'Amore 
2786*49ef7e06SGarrett D'Amore 	/* Check whether we need the header pointers for LSO segmentation */
2787*49ef7e06SGarrett D'Amore 	if (DB_LSOFLAGS(mp) & HW_LSO) {
2788*49ef7e06SGarrett D'Amore 		/* LSO segmentation relies on hardware checksum offload */
2789*49ef7e06SGarrett D'Amore 		DB_CKSUMFLAGS(mp) |= HCK_FULLCKSUM;
2790*49ef7e06SGarrett D'Amore 
2791*49ef7e06SGarrett D'Amore 		if ((mss = DB_LSOMSS(mp)) == 0) {
2792*49ef7e06SGarrett D'Amore 			rc = EINVAL;
2793*49ef7e06SGarrett D'Amore 			goto fail1;
2794*49ef7e06SGarrett D'Amore 		}
2795*49ef7e06SGarrett D'Amore 
2796*49ef7e06SGarrett D'Amore 		pkt_type = sfxge_pkthdr_parse(mp, &etherhp, &iphp, &thp,
2797*49ef7e06SGarrett D'Amore 		    &off, &size, &sport, &dport);
2798*49ef7e06SGarrett D'Amore 
2799*49ef7e06SGarrett D'Amore 		if (pkt_type != SFXGE_PACKET_TYPE_IPV4_TCP ||
2800*49ef7e06SGarrett D'Amore 		    etherhp == NULL ||
2801*49ef7e06SGarrett D'Amore 		    iphp == NULL ||
2802*49ef7e06SGarrett D'Amore 		    thp == NULL ||
2803*49ef7e06SGarrett D'Amore 		    off == 0) {
2804*49ef7e06SGarrett D'Amore 			rc = EINVAL;
2805*49ef7e06SGarrett D'Amore 			goto fail2;
2806*49ef7e06SGarrett D'Amore 		}
2807*49ef7e06SGarrett D'Amore 	}
2808*49ef7e06SGarrett D'Amore 
2809*49ef7e06SGarrett D'Amore 	/* Choose the appropriate transit queue */
2810*49ef7e06SGarrett D'Amore 	if (DB_CKSUMFLAGS(mp) & HCK_FULLCKSUM) {
2811*49ef7e06SGarrett D'Amore 		sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2812*49ef7e06SGarrett D'Amore 
2813*49ef7e06SGarrett D'Amore 		if (srsp->srs_state == SFXGE_RX_SCALE_STARTED) {
2814*49ef7e06SGarrett D'Amore 			uint32_t hash;
2815*49ef7e06SGarrett D'Amore 
2816*49ef7e06SGarrett D'Amore 			if (srsp->srs_count > 1) {
2817*49ef7e06SGarrett D'Amore 				/*
2818*49ef7e06SGarrett D'Amore 				 * If we have not already parsed the headers
2819*49ef7e06SGarrett D'Amore 				 * for LSO segmentation then we need to do it
2820*49ef7e06SGarrett D'Amore 				 * now so we can calculate the hash.
2821*49ef7e06SGarrett D'Amore 				 */
2822*49ef7e06SGarrett D'Amore 				if (thp == NULL) {
2823*49ef7e06SGarrett D'Amore 					(void) sfxge_pkthdr_parse(mp, &etherhp,
2824*49ef7e06SGarrett D'Amore 					    &iphp, &thp, &off, &size,
2825*49ef7e06SGarrett D'Amore 					    &sport, &dport);
2826*49ef7e06SGarrett D'Amore 				}
2827*49ef7e06SGarrett D'Amore 
2828*49ef7e06SGarrett D'Amore 				if (thp != NULL) {
2829*49ef7e06SGarrett D'Amore 					SFXGE_TCP_HASH(sp,
2830*49ef7e06SGarrett D'Amore 					    &iphp->ip_dst.s_addr,
2831*49ef7e06SGarrett D'Amore 					    thp->th_dport,
2832*49ef7e06SGarrett D'Amore 					    &iphp->ip_src.s_addr,
2833*49ef7e06SGarrett D'Amore 					    thp->th_sport, hash);
2834*49ef7e06SGarrett D'Amore 
2835*49ef7e06SGarrett D'Amore 					index = srsp->srs_tbl[hash %
2836*49ef7e06SGarrett D'Amore 					    SFXGE_RX_SCALE_MAX];
2837*49ef7e06SGarrett D'Amore 				} else if (iphp != NULL) {
2838*49ef7e06SGarrett D'Amore 					/*
2839*49ef7e06SGarrett D'Amore 					 * Calculate IPv4 4-tuple hash, with
2840*49ef7e06SGarrett D'Amore 					 * TCP/UDP/SCTP src/dest ports. Ports
2841*49ef7e06SGarrett D'Amore 					 * are zero for other IPv4 protocols.
2842*49ef7e06SGarrett D'Amore 					 */
2843*49ef7e06SGarrett D'Amore 					SFXGE_IP_HASH(sp,
2844*49ef7e06SGarrett D'Amore 					    &iphp->ip_dst.s_addr, dport,
2845*49ef7e06SGarrett D'Amore 					    &iphp->ip_src.s_addr, sport, hash);
2846*49ef7e06SGarrett D'Amore 
2847*49ef7e06SGarrett D'Amore 					index = srsp->srs_tbl[hash %
2848*49ef7e06SGarrett D'Amore 					    SFXGE_RX_SCALE_MAX];
2849*49ef7e06SGarrett D'Amore 				} else {
2850*49ef7e06SGarrett D'Amore 					/*
2851*49ef7e06SGarrett D'Amore 					 * Other traffic always goes to the
2852*49ef7e06SGarrett D'Amore 					 * the queue in the zero-th entry of
2853*49ef7e06SGarrett D'Amore 					 * the RSS table.
2854*49ef7e06SGarrett D'Amore 					 */
2855*49ef7e06SGarrett D'Amore 					index = srsp->srs_tbl[0];
2856*49ef7e06SGarrett D'Amore 				}
2857*49ef7e06SGarrett D'Amore 			} else {
2858*49ef7e06SGarrett D'Amore 				/*
2859*49ef7e06SGarrett D'Amore 				 * It does not matter what the hash is
2860*49ef7e06SGarrett D'Amore 				 * because all the RSS table entries will be
2861*49ef7e06SGarrett D'Amore 				 * the same.
2862*49ef7e06SGarrett D'Amore 				 */
2863*49ef7e06SGarrett D'Amore 				index = srsp->srs_tbl[0];
2864*49ef7e06SGarrett D'Amore 			}
2865*49ef7e06SGarrett D'Amore 
2866*49ef7e06SGarrett D'Amore 			/*
2867*49ef7e06SGarrett D'Amore 			 * Find the event queue corresponding to the hash in
2868*49ef7e06SGarrett D'Amore 			 * the RSS table.
2869*49ef7e06SGarrett D'Amore 			 */
2870*49ef7e06SGarrett D'Amore 			txq = sp->s_tx_scale_base[SFXGE_TXQ_IP_TCP_UDP_CKSUM] +
2871*49ef7e06SGarrett D'Amore 			    index;
2872*49ef7e06SGarrett D'Amore 			stp = sp->s_stp[txq];
2873*49ef7e06SGarrett D'Amore 			ASSERT3U(stp->st_evq, ==, index);
2874*49ef7e06SGarrett D'Amore 		} else {
2875*49ef7e06SGarrett D'Amore 			index = 0;
2876*49ef7e06SGarrett D'Amore 			txq = sp->s_tx_scale_base[SFXGE_TXQ_IP_TCP_UDP_CKSUM] +
2877*49ef7e06SGarrett D'Amore 			    index;
2878*49ef7e06SGarrett D'Amore 			stp = sp->s_stp[txq];
2879*49ef7e06SGarrett D'Amore 		}
2880*49ef7e06SGarrett D'Amore 	} else if (DB_CKSUMFLAGS(mp) & HCK_IPV4_HDRCKSUM) {
2881*49ef7e06SGarrett D'Amore 		ASSERT3U(sp->s_tx_scale_max[SFXGE_TXQ_IP_CKSUM], >=, 1);
2882*49ef7e06SGarrett D'Amore 		index = 0;
2883*49ef7e06SGarrett D'Amore 		txq = sp->s_tx_scale_base[SFXGE_TXQ_IP_CKSUM] + index;
2884*49ef7e06SGarrett D'Amore 		stp = sp->s_stp[txq];
2885*49ef7e06SGarrett D'Amore 	} else {
2886*49ef7e06SGarrett D'Amore 		/*
2887*49ef7e06SGarrett D'Amore 		 * No hardware checksum offload requested.
2888*49ef7e06SGarrett D'Amore 		 */
2889*49ef7e06SGarrett D'Amore 		sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2890*49ef7e06SGarrett D'Amore 
2891*49ef7e06SGarrett D'Amore 		if (srsp->srs_state == SFXGE_RX_SCALE_STARTED) {
2892*49ef7e06SGarrett D'Amore 			uint32_t hash = 0;
2893*49ef7e06SGarrett D'Amore 
2894*49ef7e06SGarrett D'Amore 			if (srsp->srs_count > 1) {
2895*49ef7e06SGarrett D'Amore 				if (iphp == NULL) {
2896*49ef7e06SGarrett D'Amore 					(void) sfxge_pkthdr_parse(mp, &etherhp,
2897*49ef7e06SGarrett D'Amore 					    &iphp, &thp, &off, &size,
2898*49ef7e06SGarrett D'Amore 					    &sport, &dport);
2899*49ef7e06SGarrett D'Amore 				}
2900*49ef7e06SGarrett D'Amore 
2901*49ef7e06SGarrett D'Amore 				if (iphp != NULL) {
2902*49ef7e06SGarrett D'Amore 					/*
2903*49ef7e06SGarrett D'Amore 					 * Calculate IPv4 4-tuple hash, with
2904*49ef7e06SGarrett D'Amore 					 * TCP/UDP/SCTP src/dest ports. Ports
2905*49ef7e06SGarrett D'Amore 					 * are zero for other IPv4 protocols.
2906*49ef7e06SGarrett D'Amore 					 */
2907*49ef7e06SGarrett D'Amore 					SFXGE_IP_HASH(sp,
2908*49ef7e06SGarrett D'Amore 					    &iphp->ip_dst.s_addr, dport,
2909*49ef7e06SGarrett D'Amore 					    &iphp->ip_src.s_addr, sport, hash);
2910*49ef7e06SGarrett D'Amore 
2911*49ef7e06SGarrett D'Amore 					hash = hash % SFXGE_RX_SCALE_MAX;
2912*49ef7e06SGarrett D'Amore 				}
2913*49ef7e06SGarrett D'Amore 			}
2914*49ef7e06SGarrett D'Amore 			index = srsp->srs_tbl[hash];
2915*49ef7e06SGarrett D'Amore 
2916*49ef7e06SGarrett D'Amore 			/*
2917*49ef7e06SGarrett D'Amore 			 * The RSS table (indexed by hash) gives the RXQ index,
2918*49ef7e06SGarrett D'Amore 			 * (mapped 1:1 with EVQs). Find the TXQ that results in
2919*49ef7e06SGarrett D'Amore 			 * using the same EVQ as for the RX data path.
2920*49ef7e06SGarrett D'Amore 			 */
2921*49ef7e06SGarrett D'Amore 			ASSERT3U(sp->s_tx_scale_max[SFXGE_TXQ_NON_CKSUM],
2922*49ef7e06SGarrett D'Amore 			    >, index);
2923*49ef7e06SGarrett D'Amore 			txq = sp->s_tx_scale_base[SFXGE_TXQ_NON_CKSUM] + index;
2924*49ef7e06SGarrett D'Amore 			stp = sp->s_stp[txq];
2925*49ef7e06SGarrett D'Amore 			ASSERT3U(stp->st_evq, ==, index);
2926*49ef7e06SGarrett D'Amore 		} else {
2927*49ef7e06SGarrett D'Amore 			ASSERT3U(sp->s_tx_scale_max[SFXGE_TXQ_NON_CKSUM], >, 0);
2928*49ef7e06SGarrett D'Amore 			index = 0;
2929*49ef7e06SGarrett D'Amore 			txq = sp->s_tx_scale_base[SFXGE_TXQ_NON_CKSUM] + index;
2930*49ef7e06SGarrett D'Amore 			stp = sp->s_stp[txq];
2931*49ef7e06SGarrett D'Amore 		}
2932*49ef7e06SGarrett D'Amore 
2933*49ef7e06SGarrett D'Amore 
2934*49ef7e06SGarrett D'Amore 	}
2935*49ef7e06SGarrett D'Amore 	ASSERT(stp != NULL);
2936*49ef7e06SGarrett D'Amore 
2937*49ef7e06SGarrett D'Amore 	ASSERT(mss == 0 || (DB_LSOFLAGS(mp) & HW_LSO));
2938*49ef7e06SGarrett D'Amore 
2939*49ef7e06SGarrett D'Amore 	/* Try to grab the lock */
2940*49ef7e06SGarrett D'Amore 	locked = mutex_tryenter(&(stp->st_lock));
2941*49ef7e06SGarrett D'Amore 
2942*49ef7e06SGarrett D'Amore 	if (locked) {
2943*49ef7e06SGarrett D'Amore 		/* Try to grab a packet from the pool */
2944*49ef7e06SGarrett D'Amore 		stpp = sfxge_tx_qfpp_get(stp);
2945*49ef7e06SGarrett D'Amore 	} else {
2946*49ef7e06SGarrett D'Amore 		stpp = NULL;
2947*49ef7e06SGarrett D'Amore 	}
2948*49ef7e06SGarrett D'Amore 
2949*49ef7e06SGarrett D'Amore 	if (stpp == NULL) {
2950*49ef7e06SGarrett D'Amore 		/*
2951*49ef7e06SGarrett D'Amore 		 * Either the pool was empty or we don't have the lock so
2952*49ef7e06SGarrett D'Amore 		 * allocate a new packet.
2953*49ef7e06SGarrett D'Amore 		 */
2954*49ef7e06SGarrett D'Amore 		if ((stpp = sfxge_tx_packet_create(sp)) == NULL) {
2955*49ef7e06SGarrett D'Amore 			rc = ENOSPC;
2956*49ef7e06SGarrett D'Amore 			goto fail3;
2957*49ef7e06SGarrett D'Amore 		}
2958*49ef7e06SGarrett D'Amore 	}
2959*49ef7e06SGarrett D'Amore 
2960*49ef7e06SGarrett D'Amore 	stpp->stp_mp = mp;
2961*49ef7e06SGarrett D'Amore 	stpp->stp_etherhp = etherhp;
2962*49ef7e06SGarrett D'Amore 	stpp->stp_iphp = iphp;
2963*49ef7e06SGarrett D'Amore 	stpp->stp_thp = thp;
2964*49ef7e06SGarrett D'Amore 	stpp->stp_off = off;
2965*49ef7e06SGarrett D'Amore 	stpp->stp_size = size;
2966*49ef7e06SGarrett D'Amore 	stpp->stp_mss = mss;
2967*49ef7e06SGarrett D'Amore 	stpp->stp_dpl_put_len = 0;
2968*49ef7e06SGarrett D'Amore 
2969*49ef7e06SGarrett D'Amore 	rc = sfxge_tx_qdpl_add(stp, stpp, locked);
2970*49ef7e06SGarrett D'Amore 	if (rc != 0) {
2971*49ef7e06SGarrett D'Amore 		/* ENOSPC can happen for DPL get or put list is full */
2972*49ef7e06SGarrett D'Amore 		ASSERT3U(rc, ==, ENOSPC);
2973*49ef7e06SGarrett D'Amore 
2974*49ef7e06SGarrett D'Amore 		/*
2975*49ef7e06SGarrett D'Amore 		 * Note; if this is the unlocked DPL put list full case there is
2976*49ef7e06SGarrett D'Amore 		 * no need to worry about a race with locked
2977*49ef7e06SGarrett D'Amore 		 * sfxge_tx_qdpl_swizzle() as we know that the TX DPL put list
2978*49ef7e06SGarrett D'Amore 		 * was full and would have been swizzle'd to the TX DPL get
2979*49ef7e06SGarrett D'Amore 		 * list; hence guaranteeing future TX completions and calls
2980*49ef7e06SGarrett D'Amore 		 * to mac_tx_update() via sfxge_tx_qcomplete()
2981*49ef7e06SGarrett D'Amore 		 */
2982*49ef7e06SGarrett D'Amore 		goto fail4;
2983*49ef7e06SGarrett D'Amore 	}
2984*49ef7e06SGarrett D'Amore 
2985*49ef7e06SGarrett D'Amore 	/* Try to grab the lock again */
2986*49ef7e06SGarrett D'Amore 	if (!locked)
2987*49ef7e06SGarrett D'Amore 		locked = mutex_tryenter(&(stp->st_lock));
2988*49ef7e06SGarrett D'Amore 
2989*49ef7e06SGarrett D'Amore 	if (locked) {
2990*49ef7e06SGarrett D'Amore 		/* Try to service the list */
2991*49ef7e06SGarrett D'Amore 		sfxge_tx_qdpl_service(stp);
2992*49ef7e06SGarrett D'Amore 		/* lock has been dropped */
2993*49ef7e06SGarrett D'Amore 	}
2994*49ef7e06SGarrett D'Amore 
2995*49ef7e06SGarrett D'Amore 	return (0);
2996*49ef7e06SGarrett D'Amore 
2997*49ef7e06SGarrett D'Amore fail4:
2998*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
2999*49ef7e06SGarrett D'Amore 	sfxge_tx_packet_destroy(sp, stpp);
3000*49ef7e06SGarrett D'Amore fail3:
3001*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
3002*49ef7e06SGarrett D'Amore 	if (locked)
3003*49ef7e06SGarrett D'Amore 		mutex_exit(&(stp->st_lock));
3004*49ef7e06SGarrett D'Amore fail2:
3005*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
3006*49ef7e06SGarrett D'Amore fail1:
3007*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
3008*49ef7e06SGarrett D'Amore 
3009*49ef7e06SGarrett D'Amore 	if (rc != ENOSPC)
3010*49ef7e06SGarrett D'Amore 		freemsg(mp);
3011*49ef7e06SGarrett D'Amore 	return (rc);
3012*49ef7e06SGarrett D'Amore }
3013*49ef7e06SGarrett D'Amore 
3014*49ef7e06SGarrett D'Amore void
sfxge_tx_stop(sfxge_t * sp)3015*49ef7e06SGarrett D'Amore sfxge_tx_stop(sfxge_t *sp)
3016*49ef7e06SGarrett D'Amore {
3017*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
3018*49ef7e06SGarrett D'Amore 	clock_t timeout;
3019*49ef7e06SGarrett D'Amore 	boolean_t wait_for_flush;
3020*49ef7e06SGarrett D'Amore 	int index;
3021*49ef7e06SGarrett D'Amore 
3022*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sp->s_state_lock)));
3023*49ef7e06SGarrett D'Amore 
3024*49ef7e06SGarrett D'Amore 	mutex_enter(&(sp->s_tx_flush_lock));
3025*49ef7e06SGarrett D'Amore 
3026*49ef7e06SGarrett D'Amore 	/* Flush all the queues */
3027*49ef7e06SGarrett D'Amore 	if (sp->s_hw_err == SFXGE_HW_OK) {
3028*49ef7e06SGarrett D'Amore 		wait_for_flush = B_TRUE;
3029*49ef7e06SGarrett D'Amore 	} else {
3030*49ef7e06SGarrett D'Amore 		/*
3031*49ef7e06SGarrett D'Amore 		 * Flag indicates possible hardware failure.
3032*49ef7e06SGarrett D'Amore 		 * Attempt flush but do not wait for it to complete.
3033*49ef7e06SGarrett D'Amore 		 */
3034*49ef7e06SGarrett D'Amore 		wait_for_flush = B_FALSE;
3035*49ef7e06SGarrett D'Amore 	}
3036*49ef7e06SGarrett D'Amore 
3037*49ef7e06SGarrett D'Amore 	/* Prepare queues to stop and flush the hardware ring */
3038*49ef7e06SGarrett D'Amore 	index = EFX_ARRAY_SIZE(sp->s_stp);
3039*49ef7e06SGarrett D'Amore 	while (--index >= 0) {
3040*49ef7e06SGarrett D'Amore 		if (sp->s_stp[index] != NULL)
3041*49ef7e06SGarrett D'Amore 			sfxge_tx_qflush(sp, index, wait_for_flush);
3042*49ef7e06SGarrett D'Amore 	}
3043*49ef7e06SGarrett D'Amore 
3044*49ef7e06SGarrett D'Amore 	if (wait_for_flush == B_FALSE)
3045*49ef7e06SGarrett D'Amore 		goto flush_done;
3046*49ef7e06SGarrett D'Amore 
3047*49ef7e06SGarrett D'Amore 	/* Wait upto 2sec for queue flushing to complete */
3048*49ef7e06SGarrett D'Amore 	timeout = ddi_get_lbolt() + drv_usectohz(SFXGE_TX_QFLUSH_USEC);
3049*49ef7e06SGarrett D'Amore 
3050*49ef7e06SGarrett D'Amore 	while (sp->s_tx_flush_pending > 0) {
3051*49ef7e06SGarrett D'Amore 		if (cv_timedwait(&(sp->s_tx_flush_kv), &(sp->s_tx_flush_lock),
3052*49ef7e06SGarrett D'Amore 		    timeout) < 0) {
3053*49ef7e06SGarrett D'Amore 			/* Timeout waiting for queues to flush */
3054*49ef7e06SGarrett D'Amore 			dev_info_t *dip = sp->s_dip;
3055*49ef7e06SGarrett D'Amore 
3056*49ef7e06SGarrett D'Amore 			DTRACE_PROBE(timeout);
3057*49ef7e06SGarrett D'Amore 			dev_err(dip, CE_NOTE,
3058*49ef7e06SGarrett D'Amore 			    SFXGE_CMN_ERR "tx qflush timeout");
3059*49ef7e06SGarrett D'Amore 			break;
3060*49ef7e06SGarrett D'Amore 		}
3061*49ef7e06SGarrett D'Amore 	}
3062*49ef7e06SGarrett D'Amore 
3063*49ef7e06SGarrett D'Amore flush_done:
3064*49ef7e06SGarrett D'Amore 	sp->s_tx_flush_pending = 0;
3065*49ef7e06SGarrett D'Amore 	mutex_exit(&(sp->s_tx_flush_lock));
3066*49ef7e06SGarrett D'Amore 
3067*49ef7e06SGarrett D'Amore 	/* Stop all the queues */
3068*49ef7e06SGarrett D'Amore 	index = EFX_ARRAY_SIZE(sp->s_stp);
3069*49ef7e06SGarrett D'Amore 	while (--index >= 0) {
3070*49ef7e06SGarrett D'Amore 		if (sp->s_stp[index] != NULL)
3071*49ef7e06SGarrett D'Amore 			sfxge_tx_qstop(sp, index);
3072*49ef7e06SGarrett D'Amore 	}
3073*49ef7e06SGarrett D'Amore 
3074*49ef7e06SGarrett D'Amore 	/* Tear down the transmit module */
3075*49ef7e06SGarrett D'Amore 	efx_tx_fini(enp);
3076*49ef7e06SGarrett D'Amore }
3077*49ef7e06SGarrett D'Amore 
3078*49ef7e06SGarrett D'Amore void
sfxge_tx_fini(sfxge_t * sp)3079*49ef7e06SGarrett D'Amore sfxge_tx_fini(sfxge_t *sp)
3080*49ef7e06SGarrett D'Amore {
3081*49ef7e06SGarrett D'Amore 	int index;
3082*49ef7e06SGarrett D'Amore 
3083*49ef7e06SGarrett D'Amore 	index = EFX_ARRAY_SIZE(sp->s_stp);
3084*49ef7e06SGarrett D'Amore 	while (--index >= 0) {
3085*49ef7e06SGarrett D'Amore 		if (sp->s_stp[index] != NULL)
3086*49ef7e06SGarrett D'Amore 			sfxge_tx_qfini(sp, index);
3087*49ef7e06SGarrett D'Amore 	}
3088*49ef7e06SGarrett D'Amore 
3089*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tqc);
3090*49ef7e06SGarrett D'Amore 	sp->s_tqc = NULL;
3091*49ef7e06SGarrett D'Amore 
3092*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tmc);
3093*49ef7e06SGarrett D'Amore 	sp->s_tmc = NULL;
3094*49ef7e06SGarrett D'Amore 
3095*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tbc);
3096*49ef7e06SGarrett D'Amore 	sp->s_tbc = NULL;
3097*49ef7e06SGarrett D'Amore 
3098*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_tpc);
3099*49ef7e06SGarrett D'Amore 	sp->s_tpc = NULL;
3100*49ef7e06SGarrett D'Amore }
3101