xref: /illumos-gate/usr/src/uts/common/io/sfxge/sfxge_tx.c (revision 49ef7e06)
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*49ef7e06S<