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, ðerhp, &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, ðerhp,
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, ðerhp,
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