xref: /illumos-gate/usr/src/uts/common/io/sfxge/sfxge_rx.c (revision 49ef7e06)
1*49ef7e06SGarrett D'Amore /*
2*49ef7e06SGarrett D'Amore  * Copyright (c) 2008-2016 Solarflare Communications Inc.
3*49ef7e06SGarrett D'Amore  * All rights reserved.
4*49ef7e06SGarrett D'Amore  *
5*49ef7e06SGarrett D'Amore  * Redistribution and use in source and binary forms, with or without
6*49ef7e06SGarrett D'Amore  * modification, are permitted provided that the following conditions are met:
7*49ef7e06SGarrett D'Amore  *
8*49ef7e06SGarrett D'Amore  * 1. Redistributions of source code must retain the above copyright notice,
9*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer.
10*49ef7e06SGarrett D'Amore  * 2. Redistributions in binary form must reproduce the above copyright notice,
11*49ef7e06SGarrett D'Amore  *    this list of conditions and the following disclaimer in the documentation
12*49ef7e06SGarrett D'Amore  *    and/or other materials provided with the distribution.
13*49ef7e06SGarrett D'Amore  *
14*49ef7e06SGarrett D'Amore  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15*49ef7e06SGarrett D'Amore  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16*49ef7e06SGarrett D'Amore  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17*49ef7e06SGarrett D'Amore  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18*49ef7e06SGarrett D'Amore  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19*49ef7e06SGarrett D'Amore  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20*49ef7e06SGarrett D'Amore  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21*49ef7e06SGarrett D'Amore  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22*49ef7e06SGarrett D'Amore  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23*49ef7e06SGarrett D'Amore  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24*49ef7e06SGarrett D'Amore  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*49ef7e06SGarrett D'Amore  *
26*49ef7e06SGarrett D'Amore  * The views and conclusions contained in the software and documentation are
27*49ef7e06SGarrett D'Amore  * those of the authors and should not be interpreted as representing official
28*49ef7e06SGarrett D'Amore  * policies, either expressed or implied, of the FreeBSD Project.
29*49ef7e06SGarrett D'Amore  */
30*49ef7e06SGarrett D'Amore 
31*49ef7e06SGarrett D'Amore #include <sys/types.h>
32*49ef7e06SGarrett D'Amore #include <sys/sysmacros.h>
33*49ef7e06SGarrett D'Amore #include <sys/ddi.h>
34*49ef7e06SGarrett D'Amore #include <sys/sunddi.h>
35*49ef7e06SGarrett D'Amore #include <sys/atomic.h>
36*49ef7e06SGarrett D'Amore #include <sys/stream.h>
37*49ef7e06SGarrett D'Amore #include <sys/strsun.h>
38*49ef7e06SGarrett D'Amore #include <sys/strsubr.h>
39*49ef7e06SGarrett D'Amore #include <sys/strft.h>
40*49ef7e06SGarrett D'Amore #include <sys/ksynch.h>
41*49ef7e06SGarrett D'Amore #include <sys/ethernet.h>
42*49ef7e06SGarrett D'Amore #include <sys/crc32.h>
43*49ef7e06SGarrett D'Amore #include <sys/pattr.h>
44*49ef7e06SGarrett D'Amore #include <sys/cpu.h>
45*49ef7e06SGarrett D'Amore 
46*49ef7e06SGarrett D'Amore #include <sys/ethernet.h>
47*49ef7e06SGarrett D'Amore #include <inet/ip.h>
48*49ef7e06SGarrett D'Amore 
49*49ef7e06SGarrett D'Amore #include <netinet/in.h>
50*49ef7e06SGarrett D'Amore #include <netinet/ip.h>
51*49ef7e06SGarrett D'Amore #include <netinet/tcp.h>
52*49ef7e06SGarrett D'Amore 
53*49ef7e06SGarrett D'Amore #include "sfxge.h"
54*49ef7e06SGarrett D'Amore 
55*49ef7e06SGarrett D'Amore #include "efx.h"
56*49ef7e06SGarrett D'Amore 
57*49ef7e06SGarrett D'Amore /* RXQ flush response timeout (in microseconds) */
58*49ef7e06SGarrett D'Amore #define	SFXGE_RX_QFLUSH_USEC	(2000000)
59*49ef7e06SGarrett D'Amore 
60*49ef7e06SGarrett D'Amore /* RXQ flush tries in the case of failure */
61*49ef7e06SGarrett D'Amore #define	SFXGE_RX_QFLUSH_TRIES	(5)
62*49ef7e06SGarrett D'Amore 
63*49ef7e06SGarrett D'Amore /* RXQ default packet buffer preallocation (number of packet buffers) */
64*49ef7e06SGarrett D'Amore #define	SFXGE_RX_QPREALLOC	(0)
65*49ef7e06SGarrett D'Amore 
66*49ef7e06SGarrett D'Amore /* Receive packet DMA attributes */
67*49ef7e06SGarrett D'Amore static ddi_device_acc_attr_t sfxge_rx_packet_devacc = {
68*49ef7e06SGarrett D'Amore 
69*49ef7e06SGarrett D'Amore 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
70*49ef7e06SGarrett D'Amore 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
71*49ef7e06SGarrett D'Amore 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
72*49ef7e06SGarrett D'Amore };
73*49ef7e06SGarrett D'Amore 
74*49ef7e06SGarrett D'Amore static ddi_dma_attr_t sfxge_rx_packet_dma_attr = {
75*49ef7e06SGarrett D'Amore 	DMA_ATTR_V0,		/* dma_attr_version	*/
76*49ef7e06SGarrett D'Amore 	0,			/* dma_attr_addr_lo	*/
77*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_addr_hi	*/
78*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_count_max	*/
79*49ef7e06SGarrett D'Amore 	SFXGE_CPU_CACHE_SIZE,	/* dma_attr_align	*/
80*49ef7e06SGarrett D'Amore 	0xffffffff,		/* dma_attr_burstsizes	*/
81*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_minxfer	*/
82*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_maxxfer	*/
83*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_seg		*/
84*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_sgllen	*/
85*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_granular	*/
86*49ef7e06SGarrett D'Amore 	0			/* dma_attr_flags	*/
87*49ef7e06SGarrett D'Amore };
88*49ef7e06SGarrett D'Amore 
89*49ef7e06SGarrett D'Amore /* Receive queue DMA attributes */
90*49ef7e06SGarrett D'Amore static ddi_device_acc_attr_t sfxge_rxq_devacc = {
91*49ef7e06SGarrett D'Amore 
92*49ef7e06SGarrett D'Amore 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
93*49ef7e06SGarrett D'Amore 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
94*49ef7e06SGarrett D'Amore 	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
95*49ef7e06SGarrett D'Amore };
96*49ef7e06SGarrett D'Amore 
97*49ef7e06SGarrett D'Amore static ddi_dma_attr_t sfxge_rxq_dma_attr = {
98*49ef7e06SGarrett D'Amore 	DMA_ATTR_V0,		/* dma_attr_version	*/
99*49ef7e06SGarrett D'Amore 	0,			/* dma_attr_addr_lo	*/
100*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_addr_hi	*/
101*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_count_max	*/
102*49ef7e06SGarrett D'Amore 	EFX_BUF_SIZE,		/* dma_attr_align	*/
103*49ef7e06SGarrett D'Amore 	0xffffffff,		/* dma_attr_burstsizes	*/
104*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_minxfer	*/
105*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_maxxfer	*/
106*49ef7e06SGarrett D'Amore 	0xffffffffffffffffull,	/* dma_attr_seg		*/
107*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_sgllen	*/
108*49ef7e06SGarrett D'Amore 	1,			/* dma_attr_granular	*/
109*49ef7e06SGarrett D'Amore 	0			/* dma_attr_flags	*/
110*49ef7e06SGarrett D'Amore };
111*49ef7e06SGarrett D'Amore 
112*49ef7e06SGarrett D'Amore /* Forward declaration */
113*49ef7e06SGarrett D'Amore static void sfxge_rx_qpreallocate(sfxge_rxq_t *srp, int nprealloc);
114*49ef7e06SGarrett D'Amore 
115*49ef7e06SGarrett D'Amore static int
sfxge_rx_packet_ctor(void * buf,void * arg,int kmflags)116*49ef7e06SGarrett D'Amore sfxge_rx_packet_ctor(void *buf, void *arg, int kmflags)
117*49ef7e06SGarrett D'Amore {
118*49ef7e06SGarrett D'Amore 	sfxge_rx_packet_t *srpp = buf;
119*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
120*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
121*49ef7e06SGarrett D'Amore 	int err;
122*49ef7e06SGarrett D'Amore 
123*49ef7e06SGarrett D'Amore 	ASSERT3U(sizeof (srpp->__srp_u1.__srp_s1), <=,
124*49ef7e06SGarrett D'Amore 	    sizeof (srpp->__srp_u1.__srp_pad));
125*49ef7e06SGarrett D'Amore 	ASSERT3U(sizeof (srpp->__srp_u2.__srp_s2), <=,
126*49ef7e06SGarrett D'Amore 	    sizeof (srpp->__srp_u2.__srp_pad));
127*49ef7e06SGarrett D'Amore 
128*49ef7e06SGarrett D'Amore 	bzero(buf, sizeof (sfxge_rx_packet_t));
129*49ef7e06SGarrett D'Amore 
130*49ef7e06SGarrett D'Amore 	/* Allocate a DMA handle */
131*49ef7e06SGarrett D'Amore 	err = ddi_dma_alloc_handle(dip, &sfxge_rx_packet_dma_attr,
132*49ef7e06SGarrett D'Amore 	    (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT,
133*49ef7e06SGarrett D'Amore 	    NULL, &(srpp->srp_dma_handle));
134*49ef7e06SGarrett D'Amore 	if (err != DDI_SUCCESS)
135*49ef7e06SGarrett D'Amore 		goto fail1;
136*49ef7e06SGarrett D'Amore 
137*49ef7e06SGarrett D'Amore 	return (0);
138*49ef7e06SGarrett D'Amore 
139*49ef7e06SGarrett D'Amore fail1:
140*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, err);
141*49ef7e06SGarrett D'Amore 
142*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(srpp, sfxge_rx_packet_t);
143*49ef7e06SGarrett D'Amore 
144*49ef7e06SGarrett D'Amore 	return (-1);
145*49ef7e06SGarrett D'Amore }
146*49ef7e06SGarrett D'Amore 
147*49ef7e06SGarrett D'Amore static void
sfxge_rx_packet_dtor(void * buf,void * arg)148*49ef7e06SGarrett D'Amore sfxge_rx_packet_dtor(void *buf, void *arg)
149*49ef7e06SGarrett D'Amore {
150*49ef7e06SGarrett D'Amore 	sfxge_rx_packet_t *srpp = buf;
151*49ef7e06SGarrett D'Amore 
152*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg))
153*49ef7e06SGarrett D'Amore 
154*49ef7e06SGarrett D'Amore 	/* Free the DMA handle */
155*49ef7e06SGarrett D'Amore 	ddi_dma_free_handle(&(srpp->srp_dma_handle));
156*49ef7e06SGarrett D'Amore 	srpp->srp_dma_handle = NULL;
157*49ef7e06SGarrett D'Amore 
158*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(srpp, sfxge_rx_packet_t);
159*49ef7e06SGarrett D'Amore }
160*49ef7e06SGarrett D'Amore 
161*49ef7e06SGarrett D'Amore static int
sfxge_rx_qctor(void * buf,void * arg,int kmflags)162*49ef7e06SGarrett D'Amore sfxge_rx_qctor(void *buf, void *arg, int kmflags)
163*49ef7e06SGarrett D'Amore {
164*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = buf;
165*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp = &(srp->sr_mem);
166*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
167*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_attr_t dma_attr;
168*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp;
169*49ef7e06SGarrett D'Amore 	int nprealloc;
170*49ef7e06SGarrett D'Amore 	unsigned int id;
171*49ef7e06SGarrett D'Amore 	int rc;
172*49ef7e06SGarrett D'Amore 
173*49ef7e06SGarrett D'Amore 	/* Compile-time structure layout checks */
174*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (srp->__sr_u1.__sr_s1) <=
175*49ef7e06SGarrett D'Amore 	    sizeof (srp->__sr_u1.__sr_pad));
176*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (srp->__sr_u2.__sr_s2) <=
177*49ef7e06SGarrett D'Amore 	    sizeof (srp->__sr_u2.__sr_pad));
178*49ef7e06SGarrett D'Amore 	EFX_STATIC_ASSERT(sizeof (srp->__sr_u3.__sr_s3) <=
179*49ef7e06SGarrett D'Amore 	    sizeof (srp->__sr_u3.__sr_pad));
180*49ef7e06SGarrett D'Amore 
181*49ef7e06SGarrett D'Amore 	bzero(buf, sizeof (sfxge_rxq_t));
182*49ef7e06SGarrett D'Amore 
183*49ef7e06SGarrett D'Amore 	srp->sr_sp = sp;
184*49ef7e06SGarrett D'Amore 
185*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dip	 = sp->s_dip;
186*49ef7e06SGarrett D'Amore 	dma_attr.sdba_dattrp	 = &sfxge_rxq_dma_attr;
187*49ef7e06SGarrett D'Amore 	dma_attr.sdba_callback	 = DDI_DMA_SLEEP;
188*49ef7e06SGarrett D'Amore 	dma_attr.sdba_length	 = EFX_RXQ_SIZE(sp->s_rxq_size);
189*49ef7e06SGarrett D'Amore 	dma_attr.sdba_memflags	 = DDI_DMA_CONSISTENT;
190*49ef7e06SGarrett D'Amore 	dma_attr.sdba_devaccp	 = &sfxge_rxq_devacc;
191*49ef7e06SGarrett D'Amore 	dma_attr.sdba_bindflags	 = DDI_DMA_READ | DDI_DMA_CONSISTENT;
192*49ef7e06SGarrett D'Amore 	dma_attr.sdba_maxcookies = 1;
193*49ef7e06SGarrett D'Amore 	dma_attr.sdba_zeroinit	 = B_FALSE;
194*49ef7e06SGarrett D'Amore 
195*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_dma_buffer_create(esmp, &dma_attr)) != 0)
196*49ef7e06SGarrett D'Amore 		goto fail1;
197*49ef7e06SGarrett D'Amore 
198*49ef7e06SGarrett D'Amore 	/* Allocate some buffer table entries */
199*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_sram_buf_tbl_alloc(sp, EFX_RXQ_NBUFS(sp->s_rxq_size),
200*49ef7e06SGarrett D'Amore 	    &(srp->sr_id))) != 0)
201*49ef7e06SGarrett D'Amore 		goto fail2;
202*49ef7e06SGarrett D'Amore 
203*49ef7e06SGarrett D'Amore 	/* Allocate the context array */
204*49ef7e06SGarrett D'Amore 	if ((srp->sr_srpp = kmem_zalloc(sizeof (sfxge_rx_packet_t *) *
205*49ef7e06SGarrett D'Amore 	    sp->s_rxq_size, kmflags)) == NULL) {
206*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
207*49ef7e06SGarrett D'Amore 		goto fail3;
208*49ef7e06SGarrett D'Amore 	}
209*49ef7e06SGarrett D'Amore 
210*49ef7e06SGarrett D'Amore 	/* Allocate the flow table */
211*49ef7e06SGarrett D'Amore 	if ((srp->sr_flow = kmem_zalloc(sizeof (sfxge_rx_flow_t) *
212*49ef7e06SGarrett D'Amore 	    SFXGE_MAX_FLOW, kmflags)) == NULL) {
213*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
214*49ef7e06SGarrett D'Amore 		goto fail4;
215*49ef7e06SGarrett D'Amore 	}
216*49ef7e06SGarrett D'Amore 
217*49ef7e06SGarrett D'Amore 	srp->sr_srfpp = &(srp->sr_srfp);
218*49ef7e06SGarrett D'Amore 	srp->sr_rto = drv_usectohz(200000);
219*49ef7e06SGarrett D'Amore 
220*49ef7e06SGarrett D'Amore 	srp->sr_mpp = &(srp->sr_mp);
221*49ef7e06SGarrett D'Amore 
222*49ef7e06SGarrett D'Amore 	/* Initialize the free packet pool */
223*49ef7e06SGarrett D'Amore 	srfppp = &(srp->sr_fpp);
224*49ef7e06SGarrett D'Amore 	if ((srfppp->srfpp_putp = kmem_zalloc(SFXGE_CPU_CACHE_SIZE *
225*49ef7e06SGarrett D'Amore 	    SFXGE_RX_FPP_NSLOTS, kmflags)) == NULL) {
226*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
227*49ef7e06SGarrett D'Amore 		goto fail5;
228*49ef7e06SGarrett D'Amore 	}
229*49ef7e06SGarrett D'Amore 	for (id = 0; id < SFXGE_RX_FPP_NSLOTS; id++) {
230*49ef7e06SGarrett D'Amore 		sfxge_rx_fpp_putlist_t *putp;
231*49ef7e06SGarrett D'Amore 		size_t off;
232*49ef7e06SGarrett D'Amore 
233*49ef7e06SGarrett D'Amore 		off = id * SFXGE_CPU_CACHE_SIZE;
234*49ef7e06SGarrett D'Amore 		putp = (void *)(srfppp->srfpp_putp + off);
235*49ef7e06SGarrett D'Amore 
236*49ef7e06SGarrett D'Amore 		putp->srfpl_putp = NULL;
237*49ef7e06SGarrett D'Amore 		putp->srfpl_putpp = &(putp->srfpl_putp);
238*49ef7e06SGarrett D'Amore 		mutex_init(&(putp->srfpl_lock), NULL, MUTEX_DRIVER,
239*49ef7e06SGarrett D'Amore 		    DDI_INTR_PRI(sp->s_intr.si_intr_pri));
240*49ef7e06SGarrett D'Amore 	}
241*49ef7e06SGarrett D'Amore 
242*49ef7e06SGarrett D'Amore 	cv_init(&(srp->sr_flush_kv), NULL, CV_DRIVER, NULL);
243*49ef7e06SGarrett D'Amore 
244*49ef7e06SGarrett D'Amore 	/* Preallocate some packets on the free packet pool */
245*49ef7e06SGarrett D'Amore 	nprealloc = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
246*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "rx_prealloc_pkt_buffers", SFXGE_RX_QPREALLOC);
247*49ef7e06SGarrett D'Amore 	sfxge_rx_qpreallocate(srp, nprealloc);
248*49ef7e06SGarrett D'Amore 
249*49ef7e06SGarrett D'Amore 
250*49ef7e06SGarrett D'Amore 	return (0);
251*49ef7e06SGarrett D'Amore 
252*49ef7e06SGarrett D'Amore fail5:
253*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail5);
254*49ef7e06SGarrett D'Amore 
255*49ef7e06SGarrett D'Amore 	srp->sr_mpp = NULL;
256*49ef7e06SGarrett D'Amore 
257*49ef7e06SGarrett D'Amore 	srp->sr_rto = 0;
258*49ef7e06SGarrett D'Amore 	srp->sr_srfpp = NULL;
259*49ef7e06SGarrett D'Amore 
260*49ef7e06SGarrett D'Amore 	/* Free the flow table */
261*49ef7e06SGarrett D'Amore 	kmem_free(srp->sr_flow, sizeof (sfxge_rx_flow_t) *
262*49ef7e06SGarrett D'Amore 	    SFXGE_MAX_FLOW);
263*49ef7e06SGarrett D'Amore 	srp->sr_flow = NULL;
264*49ef7e06SGarrett D'Amore 
265*49ef7e06SGarrett D'Amore fail4:
266*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
267*49ef7e06SGarrett D'Amore 
268*49ef7e06SGarrett D'Amore 	/* Free the context array */
269*49ef7e06SGarrett D'Amore 	kmem_free(srp->sr_srpp, sizeof (sfxge_rx_packet_t *) *
270*49ef7e06SGarrett D'Amore 	    sp->s_rxq_size);
271*49ef7e06SGarrett D'Amore 	srp->sr_srpp = NULL;
272*49ef7e06SGarrett D'Amore 
273*49ef7e06SGarrett D'Amore fail3:
274*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
275*49ef7e06SGarrett D'Amore 
276*49ef7e06SGarrett D'Amore 	/* Free the buffer table entries */
277*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_free(sp, srp->sr_id,
278*49ef7e06SGarrett D'Amore 	    EFX_RXQ_NBUFS(sp->s_rxq_size));
279*49ef7e06SGarrett D'Amore 	srp->sr_id = 0;
280*49ef7e06SGarrett D'Amore 
281*49ef7e06SGarrett D'Amore fail2:
282*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
283*49ef7e06SGarrett D'Amore 	/* Remove dma setup */
284*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(esmp);
285*49ef7e06SGarrett D'Amore 
286*49ef7e06SGarrett D'Amore fail1:
287*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
288*49ef7e06SGarrett D'Amore 
289*49ef7e06SGarrett D'Amore 	srp->sr_sp = NULL;
290*49ef7e06SGarrett D'Amore 
291*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(srp, sfxge_rxq_t);
292*49ef7e06SGarrett D'Amore 
293*49ef7e06SGarrett D'Amore 	return (-1);
294*49ef7e06SGarrett D'Amore }
295*49ef7e06SGarrett D'Amore 
296*49ef7e06SGarrett D'Amore static void
sfxge_rx_qdtor(void * buf,void * arg)297*49ef7e06SGarrett D'Amore sfxge_rx_qdtor(void *buf, void *arg)
298*49ef7e06SGarrett D'Amore {
299*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = buf;
300*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp = &(srp->sr_mem);
301*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
302*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
303*49ef7e06SGarrett D'Amore 	unsigned int id;
304*49ef7e06SGarrett D'Amore 
305*49ef7e06SGarrett D'Amore 	_NOTE(ARGUNUSED(arg))
306*49ef7e06SGarrett D'Amore 
307*49ef7e06SGarrett D'Amore 	cv_destroy(&(srp->sr_flush_kv));
308*49ef7e06SGarrett D'Amore 
309*49ef7e06SGarrett D'Amore 	/* Tear down the free packet pool */
310*49ef7e06SGarrett D'Amore 	for (id = 0; id < SFXGE_RX_FPP_NSLOTS; id++) {
311*49ef7e06SGarrett D'Amore 		sfxge_rx_fpp_putlist_t *putp;
312*49ef7e06SGarrett D'Amore 		size_t off;
313*49ef7e06SGarrett D'Amore 
314*49ef7e06SGarrett D'Amore 		off = id * SFXGE_CPU_CACHE_SIZE;
315*49ef7e06SGarrett D'Amore 		putp = (void *)(srfppp->srfpp_putp + off);
316*49ef7e06SGarrett D'Amore 
317*49ef7e06SGarrett D'Amore 		putp->srfpl_putpp = NULL;
318*49ef7e06SGarrett D'Amore 		mutex_destroy(&(putp->srfpl_lock));
319*49ef7e06SGarrett D'Amore 
320*49ef7e06SGarrett D'Amore 		SFXGE_OBJ_CHECK(putp, sfxge_rx_fpp_putlist_t);
321*49ef7e06SGarrett D'Amore 	}
322*49ef7e06SGarrett D'Amore 	kmem_free(srfppp->srfpp_putp, SFXGE_CPU_CACHE_SIZE *
323*49ef7e06SGarrett D'Amore 	    SFXGE_RX_FPP_NSLOTS);
324*49ef7e06SGarrett D'Amore 	srfppp->srfpp_putp = NULL;
325*49ef7e06SGarrett D'Amore 
326*49ef7e06SGarrett D'Amore 	srp->sr_mpp = NULL;
327*49ef7e06SGarrett D'Amore 
328*49ef7e06SGarrett D'Amore 	srp->sr_rto = 0;
329*49ef7e06SGarrett D'Amore 	srp->sr_srfpp = NULL;
330*49ef7e06SGarrett D'Amore 
331*49ef7e06SGarrett D'Amore 	/* Free the flow table */
332*49ef7e06SGarrett D'Amore 	kmem_free(srp->sr_flow, sizeof (sfxge_rx_flow_t) *
333*49ef7e06SGarrett D'Amore 	    SFXGE_MAX_FLOW);
334*49ef7e06SGarrett D'Amore 	srp->sr_flow = NULL;
335*49ef7e06SGarrett D'Amore 
336*49ef7e06SGarrett D'Amore 	/* Free the context array */
337*49ef7e06SGarrett D'Amore 	kmem_free(srp->sr_srpp, sizeof (sfxge_rx_packet_t *) *
338*49ef7e06SGarrett D'Amore 	    sp->s_rxq_size);
339*49ef7e06SGarrett D'Amore 	srp->sr_srpp = NULL;
340*49ef7e06SGarrett D'Amore 
341*49ef7e06SGarrett D'Amore 	/* Free the buffer table entries */
342*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_free(sp, srp->sr_id,
343*49ef7e06SGarrett D'Amore 	    EFX_RXQ_NBUFS(sp->s_rxq_size));
344*49ef7e06SGarrett D'Amore 	srp->sr_id = 0;
345*49ef7e06SGarrett D'Amore 
346*49ef7e06SGarrett D'Amore 	/* Tear down dma setup */
347*49ef7e06SGarrett D'Amore 	sfxge_dma_buffer_destroy(esmp);
348*49ef7e06SGarrett D'Amore 
349*49ef7e06SGarrett D'Amore 	SFXGE_OBJ_CHECK(srp, sfxge_rxq_t);
350*49ef7e06SGarrett D'Amore }
351*49ef7e06SGarrett D'Amore 
352*49ef7e06SGarrett D'Amore /* Note: This function takes ownership of *srpp. */
353*49ef7e06SGarrett D'Amore static inline void
sfxge_rx_qfpp_put(sfxge_rxq_t * srp,sfxge_rx_packet_t * srpp)354*49ef7e06SGarrett D'Amore sfxge_rx_qfpp_put(sfxge_rxq_t *srp, sfxge_rx_packet_t *srpp)
355*49ef7e06SGarrett D'Amore {
356*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
357*49ef7e06SGarrett D'Amore 	mblk_t *mp = srpp->srp_mp;
358*49ef7e06SGarrett D'Amore 	unsigned int id;
359*49ef7e06SGarrett D'Amore 	size_t off;
360*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_putlist_t *putp;
361*49ef7e06SGarrett D'Amore 
362*49ef7e06SGarrett D'Amore 	ASSERT3P(mp->b_next, ==, NULL);
363*49ef7e06SGarrett D'Amore 	ASSERT3P(mp->b_prev, ==, NULL);
364*49ef7e06SGarrett D'Amore 
365*49ef7e06SGarrett D'Amore 	id = CPU->cpu_seqid & SFXGE_RX_FPP_MASK;
366*49ef7e06SGarrett D'Amore 	off = id * SFXGE_CPU_CACHE_SIZE;
367*49ef7e06SGarrett D'Amore 
368*49ef7e06SGarrett D'Amore 	ASSERT3P(srpp->srp_putp, ==, srfppp->srfpp_putp);
369*49ef7e06SGarrett D'Amore 	putp = (void *)(srpp->srp_putp + off);
370*49ef7e06SGarrett D'Amore 
371*49ef7e06SGarrett D'Amore 	mutex_enter(&(putp->srfpl_lock));
372*49ef7e06SGarrett D'Amore 	putp->srfpl_count++;
373*49ef7e06SGarrett D'Amore 	*putp->srfpl_putpp = mp;
374*49ef7e06SGarrett D'Amore 	putp->srfpl_putpp = &(mp->b_next);
375*49ef7e06SGarrett D'Amore 	mutex_exit(&(putp->srfpl_lock));
376*49ef7e06SGarrett D'Amore }
377*49ef7e06SGarrett D'Amore 
378*49ef7e06SGarrett D'Amore static unsigned int
sfxge_rx_qfpp_swizzle(sfxge_rxq_t * srp)379*49ef7e06SGarrett D'Amore sfxge_rx_qfpp_swizzle(sfxge_rxq_t *srp)
380*49ef7e06SGarrett D'Amore {
381*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
382*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
383*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
384*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
385*49ef7e06SGarrett D'Amore 	unsigned int start;
386*49ef7e06SGarrett D'Amore 	unsigned int id;
387*49ef7e06SGarrett D'Amore 	mblk_t *p;
388*49ef7e06SGarrett D'Amore 	mblk_t **pp;
389*49ef7e06SGarrett D'Amore 	unsigned int count;
390*49ef7e06SGarrett D'Amore 	unsigned int loaned;
391*49ef7e06SGarrett D'Amore 
392*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
393*49ef7e06SGarrett D'Amore 
394*49ef7e06SGarrett D'Amore 	/* We want to access the put list for the current CPU last */
395*49ef7e06SGarrett D'Amore 	id = start = (CPU->cpu_seqid + 1) & SFXGE_RX_FPP_MASK;
396*49ef7e06SGarrett D'Amore 
397*49ef7e06SGarrett D'Amore 	do {
398*49ef7e06SGarrett D'Amore 		sfxge_rx_fpp_putlist_t *putp;
399*49ef7e06SGarrett D'Amore 		size_t off;
400*49ef7e06SGarrett D'Amore 
401*49ef7e06SGarrett D'Amore 		off = id * SFXGE_CPU_CACHE_SIZE;
402*49ef7e06SGarrett D'Amore 		id  = (id + 1) & SFXGE_RX_FPP_MASK;
403*49ef7e06SGarrett D'Amore 
404*49ef7e06SGarrett D'Amore 		putp = (void *)(srfppp->srfpp_putp + off);
405*49ef7e06SGarrett D'Amore 
406*49ef7e06SGarrett D'Amore 		/* Acquire the put list */
407*49ef7e06SGarrett D'Amore 		mutex_enter(&(putp->srfpl_lock));
408*49ef7e06SGarrett D'Amore 
409*49ef7e06SGarrett D'Amore 		p = putp->srfpl_putp;
410*49ef7e06SGarrett D'Amore 		pp = putp->srfpl_putpp;
411*49ef7e06SGarrett D'Amore 		count = putp->srfpl_count;
412*49ef7e06SGarrett D'Amore 
413*49ef7e06SGarrett D'Amore 		putp->srfpl_putp = NULL;
414*49ef7e06SGarrett D'Amore 		putp->srfpl_putpp = &(putp->srfpl_putp);
415*49ef7e06SGarrett D'Amore 		putp->srfpl_count = 0;
416*49ef7e06SGarrett D'Amore 
417*49ef7e06SGarrett D'Amore 		mutex_exit(&(putp->srfpl_lock));
418*49ef7e06SGarrett D'Amore 
419*49ef7e06SGarrett D'Amore 		if (p == NULL)
420*49ef7e06SGarrett D'Amore 			continue;
421*49ef7e06SGarrett D'Amore 
422*49ef7e06SGarrett D'Amore 		/* Add the list to the head of the get list */
423*49ef7e06SGarrett D'Amore 		*pp = srfppp->srfpp_get;
424*49ef7e06SGarrett D'Amore 		srfppp->srfpp_get = p;
425*49ef7e06SGarrett D'Amore 
426*49ef7e06SGarrett D'Amore 		/* Adjust the counters */
427*49ef7e06SGarrett D'Amore 		ASSERT3U(srfppp->srfpp_loaned, >=, count);
428*49ef7e06SGarrett D'Amore 		srfppp->srfpp_loaned -= count;
429*49ef7e06SGarrett D'Amore 		srfppp->srfpp_count += count;
430*49ef7e06SGarrett D'Amore 
431*49ef7e06SGarrett D'Amore #if 0
432*49ef7e06SGarrett D'Amore 		/* NOTE: this probe is disabled because it is expensive!! */
433*49ef7e06SGarrett D'Amore 		DTRACE_PROBE2(count,
434*49ef7e06SGarrett D'Amore 		    unsigned int, (id - 1) & SFXGE_RX_FPP_MASK,
435*49ef7e06SGarrett D'Amore 		    unsigned int, count);
436*49ef7e06SGarrett D'Amore #endif
437*49ef7e06SGarrett D'Amore 
438*49ef7e06SGarrett D'Amore 	} while (id != start);
439*49ef7e06SGarrett D'Amore 
440*49ef7e06SGarrett D'Amore 	/* Return the number of packets yet to appear in the put list */
441*49ef7e06SGarrett D'Amore 	loaned = srfppp->srfpp_loaned;
442*49ef7e06SGarrett D'Amore 
443*49ef7e06SGarrett D'Amore 
444*49ef7e06SGarrett D'Amore 	return (loaned);
445*49ef7e06SGarrett D'Amore }
446*49ef7e06SGarrett D'Amore 
447*49ef7e06SGarrett D'Amore 
448*49ef7e06SGarrett D'Amore #define	DB_FRTNP(mp)	((mp)->b_datap->db_frtnp)
449*49ef7e06SGarrett D'Amore 
450*49ef7e06SGarrett D'Amore static void
sfxge_rx_qfpp_empty(sfxge_rxq_t * srp)451*49ef7e06SGarrett D'Amore sfxge_rx_qfpp_empty(sfxge_rxq_t *srp)
452*49ef7e06SGarrett D'Amore {
453*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
454*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
455*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
456*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp;
457*49ef7e06SGarrett D'Amore 	mblk_t *mp;
458*49ef7e06SGarrett D'Amore 
459*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
460*49ef7e06SGarrett D'Amore 	srfppp = &(srp->sr_fpp);
461*49ef7e06SGarrett D'Amore 
462*49ef7e06SGarrett D'Amore 	/* Swizzle put list to get list */
463*49ef7e06SGarrett D'Amore 	(void) sfxge_rx_qfpp_swizzle(srp);
464*49ef7e06SGarrett D'Amore 	ASSERT3U(srfppp->srfpp_loaned, ==, 0);
465*49ef7e06SGarrett D'Amore 
466*49ef7e06SGarrett D'Amore 	mp = srfppp->srfpp_get;
467*49ef7e06SGarrett D'Amore 	srfppp->srfpp_get = NULL;
468*49ef7e06SGarrett D'Amore 
469*49ef7e06SGarrett D'Amore 	/* Free the remainder */
470*49ef7e06SGarrett D'Amore 	while (mp != NULL) {
471*49ef7e06SGarrett D'Amore 		mblk_t *next;
472*49ef7e06SGarrett D'Amore 		frtn_t *freep;
473*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
474*49ef7e06SGarrett D'Amore 
475*49ef7e06SGarrett D'Amore 		next = mp->b_next;
476*49ef7e06SGarrett D'Amore 		mp->b_next = NULL;
477*49ef7e06SGarrett D'Amore 
478*49ef7e06SGarrett D'Amore 		ASSERT3U(srfppp->srfpp_count, >, 0);
479*49ef7e06SGarrett D'Amore 		srfppp->srfpp_count--;
480*49ef7e06SGarrett D'Amore 
481*49ef7e06SGarrett D'Amore 		freep = DB_FRTNP(mp);
482*49ef7e06SGarrett D'Amore 		/*
483*49ef7e06SGarrett D'Amore 		 * ASSERT3P(freep->free_func, ==, sfxge_rx_qpacket_free);
484*49ef7e06SGarrett D'Amore 		 *   is implied by srpp test below
485*49ef7e06SGarrett D'Amore 		 */
486*49ef7e06SGarrett D'Amore 		/*LINTED*/
487*49ef7e06SGarrett D'Amore 		srpp = (sfxge_rx_packet_t *)(freep->free_arg);
488*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_mp, ==, mp);
489*49ef7e06SGarrett D'Amore 		ASSERT3P(mp->b_cont, ==, NULL);
490*49ef7e06SGarrett D'Amore 		srpp->srp_recycle = B_FALSE;
491*49ef7e06SGarrett D'Amore 
492*49ef7e06SGarrett D'Amore 		freeb(mp);
493*49ef7e06SGarrett D'Amore 
494*49ef7e06SGarrett D'Amore 		mp = next;
495*49ef7e06SGarrett D'Amore 	}
496*49ef7e06SGarrett D'Amore 	ASSERT3U(srfppp->srfpp_count, ==, 0);
497*49ef7e06SGarrett D'Amore 
498*49ef7e06SGarrett D'Amore 	srfppp->srfpp_min = 0;
499*49ef7e06SGarrett D'Amore 
500*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
501*49ef7e06SGarrett D'Amore }
502*49ef7e06SGarrett D'Amore 
503*49ef7e06SGarrett D'Amore /*
504*49ef7e06SGarrett D'Amore  * This is an estimate of all memory consumed per RX packet
505*49ef7e06SGarrett D'Amore  * it can be inaccurate but but sp->s_rx_pkt_mem_alloc mustn't drift
506*49ef7e06SGarrett D'Amore  */
507*49ef7e06SGarrett D'Amore static uint64_t
sfxge_rx_pkt_mem_approx(const sfxge_rx_packet_t * srpp)508*49ef7e06SGarrett D'Amore sfxge_rx_pkt_mem_approx(const sfxge_rx_packet_t *srpp)
509*49ef7e06SGarrett D'Amore {
510*49ef7e06SGarrett D'Amore 	return (srpp->srp_mblksize + sizeof (mblk_t) + sizeof (dblk_t) +
511*49ef7e06SGarrett D'Amore 	    sizeof (sfxge_rx_packet_t));
512*49ef7e06SGarrett D'Amore }
513*49ef7e06SGarrett D'Amore 
514*49ef7e06SGarrett D'Amore static void
sfxge_rx_qpacket_destroy(sfxge_rxq_t * srp,sfxge_rx_packet_t * srpp)515*49ef7e06SGarrett D'Amore sfxge_rx_qpacket_destroy(sfxge_rxq_t *srp, sfxge_rx_packet_t *srpp)
516*49ef7e06SGarrett D'Amore {
517*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
518*49ef7e06SGarrett D'Amore 	int64_t delta = sfxge_rx_pkt_mem_approx(srpp);
519*49ef7e06SGarrett D'Amore 
520*49ef7e06SGarrett D'Amore 	ASSERT(!(srpp->srp_recycle));
521*49ef7e06SGarrett D'Amore 	ASSERT3P(srpp->srp_mp, ==, NULL);
522*49ef7e06SGarrett D'Amore 
523*49ef7e06SGarrett D'Amore 	srpp->srp_off = 0;
524*49ef7e06SGarrett D'Amore 	srpp->srp_thp = NULL;
525*49ef7e06SGarrett D'Amore 	srpp->srp_iphp = NULL;
526*49ef7e06SGarrett D'Amore 	srpp->srp_etherhp = NULL;
527*49ef7e06SGarrett D'Amore 	srpp->srp_size = 0;
528*49ef7e06SGarrett D'Amore 	srpp->srp_flags = 0;
529*49ef7e06SGarrett D'Amore 
530*49ef7e06SGarrett D'Amore 	bzero(&(srpp->srp_free), sizeof (frtn_t));
531*49ef7e06SGarrett D'Amore 
532*49ef7e06SGarrett D'Amore 	srpp->srp_mblksize = 0;
533*49ef7e06SGarrett D'Amore 	srpp->srp_base = NULL;
534*49ef7e06SGarrett D'Amore 
535*49ef7e06SGarrett D'Amore 	/* Unbind the DMA memory from the DMA handle */
536*49ef7e06SGarrett D'Amore 	srpp->srp_addr = 0;
537*49ef7e06SGarrett D'Amore 	(void) ddi_dma_unbind_handle(srpp->srp_dma_handle);
538*49ef7e06SGarrett D'Amore 
539*49ef7e06SGarrett D'Amore 	/* Free the DMA memory */
540*49ef7e06SGarrett D'Amore 	srpp->srp_base = NULL;
541*49ef7e06SGarrett D'Amore 	ddi_dma_mem_free(&(srpp->srp_acc_handle));
542*49ef7e06SGarrett D'Amore 	srpp->srp_acc_handle = NULL;
543*49ef7e06SGarrett D'Amore 
544*49ef7e06SGarrett D'Amore 	srpp->srp_putp = NULL;
545*49ef7e06SGarrett D'Amore 	srpp->srp_srp = NULL;
546*49ef7e06SGarrett D'Amore 
547*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_rpc, srpp);
548*49ef7e06SGarrett D'Amore 	if (sp->s_rx_pkt_mem_max)
549*49ef7e06SGarrett D'Amore 		atomic_add_64(&sp->s_rx_pkt_mem_alloc, -delta);
550*49ef7e06SGarrett D'Amore }
551*49ef7e06SGarrett D'Amore 
552*49ef7e06SGarrett D'Amore static void
sfxge_rx_qpacket_free(void * arg)553*49ef7e06SGarrett D'Amore sfxge_rx_qpacket_free(void *arg)
554*49ef7e06SGarrett D'Amore {
555*49ef7e06SGarrett D'Amore 	sfxge_rx_packet_t *srpp = arg;
556*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = srpp->srp_srp;
557*49ef7e06SGarrett D'Amore 
558*49ef7e06SGarrett D'Amore 	/*
559*49ef7e06SGarrett D'Amore 	 * WARNING "man -s 9f esballoc"  states:
560*49ef7e06SGarrett D'Amore 	 * => runs sync from the thread calling freeb()
561*49ef7e06SGarrett D'Amore 	 * => must not sleep, or access data structures that could be freed
562*49ef7e06SGarrett D'Amore 	 */
563*49ef7e06SGarrett D'Amore 
564*49ef7e06SGarrett D'Amore 	/* Check whether we want to recycle the receive packets */
565*49ef7e06SGarrett D'Amore 	if (srpp->srp_recycle) {
566*49ef7e06SGarrett D'Amore 		frtn_t *freep;
567*49ef7e06SGarrett D'Amore 		mblk_t *mp;
568*49ef7e06SGarrett D'Amore 		size_t size;
569*49ef7e06SGarrett D'Amore 
570*49ef7e06SGarrett D'Amore 		freep = &(srpp->srp_free);
571*49ef7e06SGarrett D'Amore 		ASSERT3P(freep->free_func, ==, sfxge_rx_qpacket_free);
572*49ef7e06SGarrett D'Amore 		ASSERT3P(freep->free_arg, ==, (caddr_t)srpp);
573*49ef7e06SGarrett D'Amore 
574*49ef7e06SGarrett D'Amore 		/*
575*49ef7e06SGarrett D'Amore 		 * Allocate a matching mblk_t before the current one is
576*49ef7e06SGarrett D'Amore 		 * freed.
577*49ef7e06SGarrett D'Amore 		 */
578*49ef7e06SGarrett D'Amore 		size = srpp->srp_mblksize;
579*49ef7e06SGarrett D'Amore 
580*49ef7e06SGarrett D'Amore 		if ((mp = desballoc(srpp->srp_base, size, BPRI_HI,
581*49ef7e06SGarrett D'Amore 		    freep)) != NULL) {
582*49ef7e06SGarrett D'Amore 			srpp->srp_mp = mp;
583*49ef7e06SGarrett D'Amore 
584*49ef7e06SGarrett D'Amore 			/* NORMAL recycled case */
585*49ef7e06SGarrett D'Amore 			sfxge_rx_qfpp_put(srp, srpp);
586*49ef7e06SGarrett D'Amore 			return;
587*49ef7e06SGarrett D'Amore 		}
588*49ef7e06SGarrett D'Amore 	}
589*49ef7e06SGarrett D'Amore 
590*49ef7e06SGarrett D'Amore 	srpp->srp_mp = NULL;
591*49ef7e06SGarrett D'Amore 
592*49ef7e06SGarrett D'Amore 	sfxge_rx_qpacket_destroy(srp, srpp);
593*49ef7e06SGarrett D'Amore }
594*49ef7e06SGarrett D'Amore 
595*49ef7e06SGarrett D'Amore static sfxge_rx_packet_t *
sfxge_rx_qpacket_create(sfxge_rxq_t * srp)596*49ef7e06SGarrett D'Amore sfxge_rx_qpacket_create(sfxge_rxq_t *srp)
597*49ef7e06SGarrett D'Amore {
598*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
599*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
600*49ef7e06SGarrett D'Amore 	sfxge_rx_packet_t *srpp;
601*49ef7e06SGarrett D'Amore 	size_t size;
602*49ef7e06SGarrett D'Amore 	caddr_t base;
603*49ef7e06SGarrett D'Amore 	size_t unit;
604*49ef7e06SGarrett D'Amore 	ddi_dma_cookie_t dmac;
605*49ef7e06SGarrett D'Amore 	unsigned int ncookies;
606*49ef7e06SGarrett D'Amore 	frtn_t *freep;
607*49ef7e06SGarrett D'Amore 	mblk_t *mp;
608*49ef7e06SGarrett D'Amore 	int err;
609*49ef7e06SGarrett D'Amore 	int rc;
610*49ef7e06SGarrett D'Amore 
611*49ef7e06SGarrett D'Amore 	size = sp->s_rx_buffer_size;
612*49ef7e06SGarrett D'Amore 
613*49ef7e06SGarrett D'Amore 	if (sp->s_rx_pkt_mem_max &&
614*49ef7e06SGarrett D'Amore 	    (sp->s_rx_pkt_mem_alloc + size >= sp->s_rx_pkt_mem_max)) {
615*49ef7e06SGarrett D'Amore 		DTRACE_PROBE(rx_pkt_mem_max);
616*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_rx_pkt_mem_limit++;
617*49ef7e06SGarrett D'Amore 		return (NULL);
618*49ef7e06SGarrett D'Amore 	}
619*49ef7e06SGarrett D'Amore 
620*49ef7e06SGarrett D'Amore 	/* Allocate a new packet */
621*49ef7e06SGarrett D'Amore 	if ((srpp = kmem_cache_alloc(sp->s_rpc, KM_NOSLEEP)) == NULL) {
622*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_kcache_alloc_nomem++;
623*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
624*49ef7e06SGarrett D'Amore 		goto fail1;
625*49ef7e06SGarrett D'Amore 	}
626*49ef7e06SGarrett D'Amore 
627*49ef7e06SGarrett D'Amore 	srpp->srp_srp = srp;
628*49ef7e06SGarrett D'Amore 	srpp->srp_putp = srfppp->srfpp_putp;
629*49ef7e06SGarrett D'Amore 
630*49ef7e06SGarrett D'Amore 	/* Allocate some DMA memory */
631*49ef7e06SGarrett D'Amore 	err = ddi_dma_mem_alloc(srpp->srp_dma_handle, size,
632*49ef7e06SGarrett D'Amore 	    &sfxge_rx_packet_devacc, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT,
633*49ef7e06SGarrett D'Amore 	    NULL, &base, &unit, &(srpp->srp_acc_handle));
634*49ef7e06SGarrett D'Amore 	switch (err) {
635*49ef7e06SGarrett D'Amore 	case DDI_SUCCESS:
636*49ef7e06SGarrett D'Amore 		break;
637*49ef7e06SGarrett D'Amore 
638*49ef7e06SGarrett D'Amore 	case DDI_FAILURE:
639*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_alloc_nomem++;
640*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
641*49ef7e06SGarrett D'Amore 		goto fail2;
642*49ef7e06SGarrett D'Amore 
643*49ef7e06SGarrett D'Amore 	default:
644*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_alloc_fail++;
645*49ef7e06SGarrett D'Amore 		rc = EFAULT;
646*49ef7e06SGarrett D'Amore 		goto fail2;
647*49ef7e06SGarrett D'Amore 	}
648*49ef7e06SGarrett D'Amore 
649*49ef7e06SGarrett D'Amore 	/* Adjust the buffer to align the start of the DMA area correctly */
650*49ef7e06SGarrett D'Amore 	base += sp->s_rx_buffer_align;
651*49ef7e06SGarrett D'Amore 	size -= sp->s_rx_buffer_align;
652*49ef7e06SGarrett D'Amore 
653*49ef7e06SGarrett D'Amore 	/* Bind the DMA memory to the DMA handle */
654*49ef7e06SGarrett D'Amore 	err = ddi_dma_addr_bind_handle(srpp->srp_dma_handle, NULL,
655*49ef7e06SGarrett D'Amore 	    base, size, DDI_DMA_READ | DDI_DMA_STREAMING,
656*49ef7e06SGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &dmac, &ncookies);
657*49ef7e06SGarrett D'Amore 	switch (err) {
658*49ef7e06SGarrett D'Amore 	case DDI_DMA_MAPPED:
659*49ef7e06SGarrett D'Amore 		break;
660*49ef7e06SGarrett D'Amore 
661*49ef7e06SGarrett D'Amore 	case DDI_DMA_INUSE:
662*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_bind_fail++;
663*49ef7e06SGarrett D'Amore 		rc = EEXIST;
664*49ef7e06SGarrett D'Amore 		goto fail3;
665*49ef7e06SGarrett D'Amore 
666*49ef7e06SGarrett D'Amore 	case DDI_DMA_NORESOURCES:
667*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_bind_nomem++;
668*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
669*49ef7e06SGarrett D'Amore 		goto fail3;
670*49ef7e06SGarrett D'Amore 
671*49ef7e06SGarrett D'Amore 	case DDI_DMA_NOMAPPING:
672*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_bind_fail++;
673*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
674*49ef7e06SGarrett D'Amore 		goto fail3;
675*49ef7e06SGarrett D'Amore 
676*49ef7e06SGarrett D'Amore 	case DDI_DMA_TOOBIG:
677*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_bind_fail++;
678*49ef7e06SGarrett D'Amore 		rc = EFBIG;
679*49ef7e06SGarrett D'Amore 		goto fail3;
680*49ef7e06SGarrett D'Amore 
681*49ef7e06SGarrett D'Amore 	default:
682*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_dma_bind_fail++;
683*49ef7e06SGarrett D'Amore 		rc = EFAULT;
684*49ef7e06SGarrett D'Amore 		goto fail3;
685*49ef7e06SGarrett D'Amore 	}
686*49ef7e06SGarrett D'Amore 	ASSERT3U(ncookies, ==, 1);
687*49ef7e06SGarrett D'Amore 
688*49ef7e06SGarrett D'Amore 	srpp->srp_addr = dmac.dmac_laddress;
689*49ef7e06SGarrett D'Amore 
690*49ef7e06SGarrett D'Amore 	srpp->srp_base = (unsigned char *)base;
691*49ef7e06SGarrett D'Amore 	srpp->srp_mblksize = size;
692*49ef7e06SGarrett D'Amore 
693*49ef7e06SGarrett D'Amore 	/*
694*49ef7e06SGarrett D'Amore 	 * Allocate a STREAMS block: We use size 1 so that the allocator will
695*49ef7e06SGarrett D'Amore 	 * use the first (and smallest) dblk cache.
696*49ef7e06SGarrett D'Amore 	 */
697*49ef7e06SGarrett D'Amore 	freep = &(srpp->srp_free);
698*49ef7e06SGarrett D'Amore 	freep->free_func = sfxge_rx_qpacket_free;
699*49ef7e06SGarrett D'Amore 	freep->free_arg  = (caddr_t)srpp;
700*49ef7e06SGarrett D'Amore 
701*49ef7e06SGarrett D'Amore 	if ((mp = desballoc(srpp->srp_base, size, BPRI_HI, freep)) == NULL) {
702*49ef7e06SGarrett D'Amore 		srp->sr_kstat.srk_desballoc_fail++;
703*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
704*49ef7e06SGarrett D'Amore 		goto fail4;
705*49ef7e06SGarrett D'Amore 	}
706*49ef7e06SGarrett D'Amore 
707*49ef7e06SGarrett D'Amore 	srpp->srp_mp = mp;
708*49ef7e06SGarrett D'Amore 	srpp->srp_recycle = B_TRUE;
709*49ef7e06SGarrett D'Amore 
710*49ef7e06SGarrett D'Amore 	if (sp->s_rx_pkt_mem_max) {
711*49ef7e06SGarrett D'Amore 		int64_t delta = sfxge_rx_pkt_mem_approx(srpp);
712*49ef7e06SGarrett D'Amore 		atomic_add_64(&sp->s_rx_pkt_mem_alloc, delta);
713*49ef7e06SGarrett D'Amore 	}
714*49ef7e06SGarrett D'Amore 
715*49ef7e06SGarrett D'Amore 	return (srpp);
716*49ef7e06SGarrett D'Amore 
717*49ef7e06SGarrett D'Amore fail4:
718*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
719*49ef7e06SGarrett D'Amore 
720*49ef7e06SGarrett D'Amore 	bzero(&(srpp->srp_free), sizeof (frtn_t));
721*49ef7e06SGarrett D'Amore 
722*49ef7e06SGarrett D'Amore 	srpp->srp_mblksize = 0;
723*49ef7e06SGarrett D'Amore 	srpp->srp_base = NULL;
724*49ef7e06SGarrett D'Amore 
725*49ef7e06SGarrett D'Amore 	/* Unbind the DMA memory from the DMA handle */
726*49ef7e06SGarrett D'Amore 	srpp->srp_addr = 0;
727*49ef7e06SGarrett D'Amore 	(void) ddi_dma_unbind_handle(srpp->srp_dma_handle);
728*49ef7e06SGarrett D'Amore 
729*49ef7e06SGarrett D'Amore fail3:
730*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
731*49ef7e06SGarrett D'Amore 
732*49ef7e06SGarrett D'Amore 	/* Free the DMA memory */
733*49ef7e06SGarrett D'Amore 	ddi_dma_mem_free(&(srpp->srp_acc_handle));
734*49ef7e06SGarrett D'Amore 	srpp->srp_acc_handle = NULL;
735*49ef7e06SGarrett D'Amore 
736*49ef7e06SGarrett D'Amore fail2:
737*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
738*49ef7e06SGarrett D'Amore 
739*49ef7e06SGarrett D'Amore 	srpp->srp_putp = NULL;
740*49ef7e06SGarrett D'Amore 	srpp->srp_srp = NULL;
741*49ef7e06SGarrett D'Amore 
742*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_rpc, srpp);
743*49ef7e06SGarrett D'Amore 
744*49ef7e06SGarrett D'Amore fail1:
745*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
746*49ef7e06SGarrett D'Amore 
747*49ef7e06SGarrett D'Amore 	return (NULL);
748*49ef7e06SGarrett D'Amore }
749*49ef7e06SGarrett D'Amore 
750*49ef7e06SGarrett D'Amore #define	SFXGE_REFILL_BATCH  64
751*49ef7e06SGarrett D'Amore 
752*49ef7e06SGarrett D'Amore /* Try to refill the RX descriptor ring from the associated free pkt pool */
753*49ef7e06SGarrett D'Amore static void
sfxge_rx_qrefill(sfxge_rxq_t * srp,unsigned int target)754*49ef7e06SGarrett D'Amore sfxge_rx_qrefill(sfxge_rxq_t *srp, unsigned int target)
755*49ef7e06SGarrett D'Amore {
756*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
757*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
758*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
759*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
760*49ef7e06SGarrett D'Amore 	efsys_dma_addr_t addr[SFXGE_REFILL_BATCH];
761*49ef7e06SGarrett D'Amore 	mblk_t *mp;
762*49ef7e06SGarrett D'Amore 	int ntodo;
763*49ef7e06SGarrett D'Amore 	unsigned int count;
764*49ef7e06SGarrett D'Amore 	unsigned int batch;
765*49ef7e06SGarrett D'Amore 	unsigned int rxfill;
766*49ef7e06SGarrett D'Amore 	unsigned int mblksize;
767*49ef7e06SGarrett D'Amore 
768*49ef7e06SGarrett D'Amore 	prefetch_read_many(sp->s_enp);
769*49ef7e06SGarrett D'Amore 	prefetch_read_many(srp->sr_erp);
770*49ef7e06SGarrett D'Amore 
771*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
772*49ef7e06SGarrett D'Amore 
773*49ef7e06SGarrett D'Amore 	if (srp->sr_state != SFXGE_RXQ_STARTED)
774*49ef7e06SGarrett D'Amore 		return;
775*49ef7e06SGarrett D'Amore 
776*49ef7e06SGarrett D'Amore 	rxfill = srp->sr_added - srp->sr_completed;
777*49ef7e06SGarrett D'Amore 	ASSERT3U(rxfill, <=, EFX_RXQ_LIMIT(sp->s_rxq_size));
778*49ef7e06SGarrett D'Amore 	ntodo = min(EFX_RXQ_LIMIT(sp->s_rxq_size) - rxfill, target);
779*49ef7e06SGarrett D'Amore 	ASSERT3U(ntodo, <=, EFX_RXQ_LIMIT(sp->s_rxq_size));
780*49ef7e06SGarrett D'Amore 
781*49ef7e06SGarrett D'Amore 	if (ntodo == 0)
782*49ef7e06SGarrett D'Amore 		goto out;
783*49ef7e06SGarrett D'Amore 
784*49ef7e06SGarrett D'Amore 	(void) sfxge_rx_qfpp_swizzle(srp);
785*49ef7e06SGarrett D'Amore 
786*49ef7e06SGarrett D'Amore 	mp = srfppp->srfpp_get;
787*49ef7e06SGarrett D'Amore 	count = srfppp->srfpp_count;
788*49ef7e06SGarrett D'Amore 	mblksize = sp->s_rx_buffer_size - sp->s_rx_buffer_align;
789*49ef7e06SGarrett D'Amore 
790*49ef7e06SGarrett D'Amore 	batch = 0;
791*49ef7e06SGarrett D'Amore 	while (ntodo-- > 0) {
792*49ef7e06SGarrett D'Amore 		mblk_t *next;
793*49ef7e06SGarrett D'Amore 		frtn_t *freep;
794*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
795*49ef7e06SGarrett D'Amore 		unsigned int id;
796*49ef7e06SGarrett D'Amore 
797*49ef7e06SGarrett D'Amore 		if (mp == NULL)
798*49ef7e06SGarrett D'Amore 			break;
799*49ef7e06SGarrett D'Amore 
800*49ef7e06SGarrett D'Amore 		next = mp->b_next;
801*49ef7e06SGarrett D'Amore 		mp->b_next = NULL;
802*49ef7e06SGarrett D'Amore 
803*49ef7e06SGarrett D'Amore 		if (next != NULL)
804*49ef7e06SGarrett D'Amore 			prefetch_read_many(next);
805*49ef7e06SGarrett D'Amore 
806*49ef7e06SGarrett D'Amore 		freep = DB_FRTNP(mp);
807*49ef7e06SGarrett D'Amore 		/*LINTED*/
808*49ef7e06SGarrett D'Amore 		srpp = (sfxge_rx_packet_t *)(freep->free_arg);
809*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_mp, ==, mp);
810*49ef7e06SGarrett D'Amore 
811*49ef7e06SGarrett D'Amore 		/* The MTU may have changed since the packet was allocated */
812*49ef7e06SGarrett D'Amore 		if (MBLKSIZE(mp) != mblksize) {
813*49ef7e06SGarrett D'Amore 			srpp->srp_recycle = B_FALSE;
814*49ef7e06SGarrett D'Amore 
815*49ef7e06SGarrett D'Amore 			freeb(mp);
816*49ef7e06SGarrett D'Amore 
817*49ef7e06SGarrett D'Amore 			--count;
818*49ef7e06SGarrett D'Amore 			mp = next;
819*49ef7e06SGarrett D'Amore 			continue;
820*49ef7e06SGarrett D'Amore 		}
821*49ef7e06SGarrett D'Amore 
822*49ef7e06SGarrett D'Amore 		srpp->srp_off = 0;
823*49ef7e06SGarrett D'Amore 		srpp->srp_thp = NULL;
824*49ef7e06SGarrett D'Amore 		srpp->srp_iphp = NULL;
825*49ef7e06SGarrett D'Amore 		srpp->srp_etherhp = NULL;
826*49ef7e06SGarrett D'Amore 		srpp->srp_size = 0;
827*49ef7e06SGarrett D'Amore 		srpp->srp_flags = EFX_DISCARD;
828*49ef7e06SGarrett D'Amore 
829*49ef7e06SGarrett D'Amore 		id = (srp->sr_added + batch) & (sp->s_rxq_size - 1);
830*49ef7e06SGarrett D'Amore 		ASSERT(srp->sr_srpp[id] == NULL);
831*49ef7e06SGarrett D'Amore 		srp->sr_srpp[id] = srpp;
832*49ef7e06SGarrett D'Amore 
833*49ef7e06SGarrett D'Amore 		addr[batch++] = srpp->srp_addr;
834*49ef7e06SGarrett D'Amore 		if (batch == SFXGE_REFILL_BATCH) {
835*49ef7e06SGarrett D'Amore 			efx_rx_qpost(srp->sr_erp, addr, mblksize, batch,
836*49ef7e06SGarrett D'Amore 			    srp->sr_completed, srp->sr_added);
837*49ef7e06SGarrett D'Amore 			srp->sr_added += batch;
838*49ef7e06SGarrett D'Amore 			batch = 0;
839*49ef7e06SGarrett D'Amore 		}
840*49ef7e06SGarrett D'Amore 
841*49ef7e06SGarrett D'Amore 		--count;
842*49ef7e06SGarrett D'Amore 		mp = next;
843*49ef7e06SGarrett D'Amore 	}
844*49ef7e06SGarrett D'Amore 
845*49ef7e06SGarrett D'Amore 	srfppp->srfpp_get = mp;
846*49ef7e06SGarrett D'Amore 	srfppp->srfpp_count = count;
847*49ef7e06SGarrett D'Amore 
848*49ef7e06SGarrett D'Amore 	if (batch != 0) {
849*49ef7e06SGarrett D'Amore 		efx_rx_qpost(srp->sr_erp, addr, mblksize, batch,
850*49ef7e06SGarrett D'Amore 		    srp->sr_completed, srp->sr_added);
851*49ef7e06SGarrett D'Amore 		srp->sr_added += batch;
852*49ef7e06SGarrett D'Amore 	}
853*49ef7e06SGarrett D'Amore 
854*49ef7e06SGarrett D'Amore 	efx_rx_qpush(srp->sr_erp, srp->sr_added, &srp->sr_pushed);
855*49ef7e06SGarrett D'Amore 
856*49ef7e06SGarrett D'Amore out:
857*49ef7e06SGarrett D'Amore 	if (srfppp->srfpp_count < srfppp->srfpp_min)
858*49ef7e06SGarrett D'Amore 		srfppp->srfpp_min = srfppp->srfpp_count;
859*49ef7e06SGarrett D'Amore }
860*49ef7e06SGarrett D'Amore 
861*49ef7e06SGarrett D'Amore /* Preallocate packets and put them in the free packet pool */
862*49ef7e06SGarrett D'Amore static void
sfxge_rx_qpreallocate(sfxge_rxq_t * srp,int nprealloc)863*49ef7e06SGarrett D'Amore sfxge_rx_qpreallocate(sfxge_rxq_t *srp, int nprealloc)
864*49ef7e06SGarrett D'Amore {
865*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &((srp)->sr_fpp);
866*49ef7e06SGarrett D'Amore 	srfppp->srfpp_lowat = nprealloc;
867*49ef7e06SGarrett D'Amore 	while (nprealloc-- > 0) {
868*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
869*49ef7e06SGarrett D'Amore 
870*49ef7e06SGarrett D'Amore 		if ((srpp = sfxge_rx_qpacket_create(srp)) == NULL)
871*49ef7e06SGarrett D'Amore 			break;
872*49ef7e06SGarrett D'Amore 		sfxge_rx_qfpp_put(srp, srpp);
873*49ef7e06SGarrett D'Amore 	}
874*49ef7e06SGarrett D'Amore }
875*49ef7e06SGarrett D'Amore 
876*49ef7e06SGarrett D'Amore /* Try to refill the RX descriptor ring by allocating new packets */
877*49ef7e06SGarrett D'Amore static void
sfxge_rx_qfill(sfxge_rxq_t * srp,unsigned int target)878*49ef7e06SGarrett D'Amore sfxge_rx_qfill(sfxge_rxq_t *srp, unsigned int target)
879*49ef7e06SGarrett D'Amore {
880*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
881*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
882*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
883*49ef7e06SGarrett D'Amore 	unsigned int batch;
884*49ef7e06SGarrett D'Amore 	unsigned int rxfill;
885*49ef7e06SGarrett D'Amore 	unsigned int mblksize;
886*49ef7e06SGarrett D'Amore 	int ntodo;
887*49ef7e06SGarrett D'Amore 	efsys_dma_addr_t addr[SFXGE_REFILL_BATCH];
888*49ef7e06SGarrett D'Amore 	mblk_t *mp = NULL;
889*49ef7e06SGarrett D'Amore 
890*49ef7e06SGarrett D'Amore 	prefetch_read_many(sp->s_enp);
891*49ef7e06SGarrett D'Amore 	prefetch_read_many(srp->sr_erp);
892*49ef7e06SGarrett D'Amore 
893*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
894*49ef7e06SGarrett D'Amore 
895*49ef7e06SGarrett D'Amore 	if (srp->sr_state != SFXGE_RXQ_STARTED)
896*49ef7e06SGarrett D'Amore 		return;
897*49ef7e06SGarrett D'Amore 
898*49ef7e06SGarrett D'Amore 	rxfill = srp->sr_added - srp->sr_completed;
899*49ef7e06SGarrett D'Amore 	ASSERT3U(rxfill, <=, EFX_RXQ_LIMIT(sp->s_rxq_size));
900*49ef7e06SGarrett D'Amore 	ntodo = min(EFX_RXQ_LIMIT(sp->s_rxq_size) - rxfill, target);
901*49ef7e06SGarrett D'Amore 	ASSERT3U(ntodo, <=, EFX_RXQ_LIMIT(sp->s_rxq_size));
902*49ef7e06SGarrett D'Amore 
903*49ef7e06SGarrett D'Amore 	if (ntodo == 0)
904*49ef7e06SGarrett D'Amore 		return;
905*49ef7e06SGarrett D'Amore 
906*49ef7e06SGarrett D'Amore 	mblksize = sp->s_rx_buffer_size - sp->s_rx_buffer_align;
907*49ef7e06SGarrett D'Amore 
908*49ef7e06SGarrett D'Amore 	batch = 0;
909*49ef7e06SGarrett D'Amore 	while (ntodo-- > 0) {
910*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
911*49ef7e06SGarrett D'Amore 		unsigned int id;
912*49ef7e06SGarrett D'Amore 
913*49ef7e06SGarrett D'Amore 		if ((srpp = sfxge_rx_qpacket_create(srp)) == NULL)
914*49ef7e06SGarrett D'Amore 			break;
915*49ef7e06SGarrett D'Amore 
916*49ef7e06SGarrett D'Amore 		mp = srpp->srp_mp;
917*49ef7e06SGarrett D'Amore 
918*49ef7e06SGarrett D'Amore 		ASSERT3U(MBLKSIZE(mp), ==, mblksize);
919*49ef7e06SGarrett D'Amore 
920*49ef7e06SGarrett D'Amore 		ASSERT3U(srpp->srp_off, ==, 0);
921*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_thp, ==, NULL);
922*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_iphp, ==, NULL);
923*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_etherhp, ==, NULL);
924*49ef7e06SGarrett D'Amore 		ASSERT3U(srpp->srp_size, ==, 0);
925*49ef7e06SGarrett D'Amore 
926*49ef7e06SGarrett D'Amore 		srpp->srp_flags = EFX_DISCARD;
927*49ef7e06SGarrett D'Amore 
928*49ef7e06SGarrett D'Amore 		id = (srp->sr_added + batch) & (sp->s_rxq_size - 1);
929*49ef7e06SGarrett D'Amore 		ASSERT(srp->sr_srpp[id] == NULL);
930*49ef7e06SGarrett D'Amore 		srp->sr_srpp[id] = srpp;
931*49ef7e06SGarrett D'Amore 
932*49ef7e06SGarrett D'Amore 		addr[batch++] = srpp->srp_addr;
933*49ef7e06SGarrett D'Amore 		if (batch == SFXGE_REFILL_BATCH) {
934*49ef7e06SGarrett D'Amore 			efx_rx_qpost(srp->sr_erp, addr, mblksize, batch,
935*49ef7e06SGarrett D'Amore 			    srp->sr_completed, srp->sr_added);
936*49ef7e06SGarrett D'Amore 			srp->sr_added += batch;
937*49ef7e06SGarrett D'Amore 			batch = 0;
938*49ef7e06SGarrett D'Amore 		}
939*49ef7e06SGarrett D'Amore 	}
940*49ef7e06SGarrett D'Amore 
941*49ef7e06SGarrett D'Amore 	if (batch != 0) {
942*49ef7e06SGarrett D'Amore 		efx_rx_qpost(srp->sr_erp, addr, mblksize, batch,
943*49ef7e06SGarrett D'Amore 		    srp->sr_completed, srp->sr_added);
944*49ef7e06SGarrett D'Amore 		srp->sr_added += batch;
945*49ef7e06SGarrett D'Amore 	}
946*49ef7e06SGarrett D'Amore 
947*49ef7e06SGarrett D'Amore 	efx_rx_qpush(srp->sr_erp, srp->sr_added, &srp->sr_pushed);
948*49ef7e06SGarrett D'Amore }
949*49ef7e06SGarrett D'Amore 
950*49ef7e06SGarrett D'Amore void
sfxge_rx_qfpp_trim(sfxge_rxq_t * srp)951*49ef7e06SGarrett D'Amore sfxge_rx_qfpp_trim(sfxge_rxq_t *srp)
952*49ef7e06SGarrett D'Amore {
953*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
954*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
955*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
956*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
957*49ef7e06SGarrett D'Amore 	mblk_t *p;
958*49ef7e06SGarrett D'Amore 	mblk_t **pp;
959*49ef7e06SGarrett D'Amore 	int count;
960*49ef7e06SGarrett D'Amore 
961*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
962*49ef7e06SGarrett D'Amore 
963*49ef7e06SGarrett D'Amore 	if (srp->sr_state != SFXGE_RXQ_STARTED)
964*49ef7e06SGarrett D'Amore 		goto done;
965*49ef7e06SGarrett D'Amore 
966*49ef7e06SGarrett D'Amore 	/* Make sure the queue is full */
967*49ef7e06SGarrett D'Amore 	sfxge_rx_qrefill(srp, EFX_RXQ_LIMIT(sp->s_rxq_size));
968*49ef7e06SGarrett D'Amore 
969*49ef7e06SGarrett D'Amore 	/* The refill may have emptied the pool */
970*49ef7e06SGarrett D'Amore 	if (srfppp->srfpp_min == 0)
971*49ef7e06SGarrett D'Amore 		goto done;
972*49ef7e06SGarrett D'Amore 
973*49ef7e06SGarrett D'Amore 	/* Don't trim below the pool's low water mark */
974*49ef7e06SGarrett D'Amore 	if (srfppp->srfpp_count <= srfppp->srfpp_lowat)
975*49ef7e06SGarrett D'Amore 		goto done;
976*49ef7e06SGarrett D'Amore 
977*49ef7e06SGarrett D'Amore 	ASSERT(srfppp->srfpp_min <= srfppp->srfpp_count);
978*49ef7e06SGarrett D'Amore 
979*49ef7e06SGarrett D'Amore 	/* Trim to the largest of srfppp->srfpp_min and srfpp->srfpp_lowat */
980*49ef7e06SGarrett D'Amore 	if (srfppp->srfpp_lowat > srfppp->srfpp_min)
981*49ef7e06SGarrett D'Amore 		count = srfppp->srfpp_count - srfppp->srfpp_lowat;
982*49ef7e06SGarrett D'Amore 	else
983*49ef7e06SGarrett D'Amore 		count = srfppp->srfpp_count - srfppp->srfpp_min;
984*49ef7e06SGarrett D'Amore 
985*49ef7e06SGarrett D'Amore 	/* Walk the get list */
986*49ef7e06SGarrett D'Amore 	pp = &(srfppp->srfpp_get);
987*49ef7e06SGarrett D'Amore 	while (--count >= 0) {
988*49ef7e06SGarrett D'Amore 		ASSERT(pp);
989*49ef7e06SGarrett D'Amore 		p = *pp;
990*49ef7e06SGarrett D'Amore 		ASSERT(p != NULL);
991*49ef7e06SGarrett D'Amore 
992*49ef7e06SGarrett D'Amore 		pp = &(p->b_next);
993*49ef7e06SGarrett D'Amore 	}
994*49ef7e06SGarrett D'Amore 	ASSERT(pp);
995*49ef7e06SGarrett D'Amore 	p = *pp;
996*49ef7e06SGarrett D'Amore 
997*49ef7e06SGarrett D'Amore 	/* Truncate the get list */
998*49ef7e06SGarrett D'Amore 	*pp = NULL;
999*49ef7e06SGarrett D'Amore 
1000*49ef7e06SGarrett D'Amore 	/* Free the remainder */
1001*49ef7e06SGarrett D'Amore 	while (p != NULL) {
1002*49ef7e06SGarrett D'Amore 		mblk_t *next;
1003*49ef7e06SGarrett D'Amore 		frtn_t *freep;
1004*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
1005*49ef7e06SGarrett D'Amore 
1006*49ef7e06SGarrett D'Amore 		next = p->b_next;
1007*49ef7e06SGarrett D'Amore 		p->b_next = NULL;
1008*49ef7e06SGarrett D'Amore 
1009*49ef7e06SGarrett D'Amore 		ASSERT3U(srfppp->srfpp_min, >, 0);
1010*49ef7e06SGarrett D'Amore 		srfppp->srfpp_min--;
1011*49ef7e06SGarrett D'Amore 		srfppp->srfpp_count--;
1012*49ef7e06SGarrett D'Amore 
1013*49ef7e06SGarrett D'Amore 		freep = DB_FRTNP(p);
1014*49ef7e06SGarrett D'Amore 		/*LINTED*/
1015*49ef7e06SGarrett D'Amore 		srpp = (sfxge_rx_packet_t *)(freep->free_arg);
1016*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_mp, ==, p);
1017*49ef7e06SGarrett D'Amore 
1018*49ef7e06SGarrett D'Amore 		srpp->srp_recycle = B_FALSE;
1019*49ef7e06SGarrett D'Amore 
1020*49ef7e06SGarrett D'Amore 		freeb(p);
1021*49ef7e06SGarrett D'Amore 
1022*49ef7e06SGarrett D'Amore 		p = next;
1023*49ef7e06SGarrett D'Amore 	}
1024*49ef7e06SGarrett D'Amore 
1025*49ef7e06SGarrett D'Amore done:
1026*49ef7e06SGarrett D'Amore 	srfppp->srfpp_min = srfppp->srfpp_count;
1027*49ef7e06SGarrett D'Amore }
1028*49ef7e06SGarrett D'Amore 
1029*49ef7e06SGarrett D'Amore static void
sfxge_rx_qpoll(void * arg)1030*49ef7e06SGarrett D'Amore sfxge_rx_qpoll(void *arg)
1031*49ef7e06SGarrett D'Amore {
1032*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = arg;
1033*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1034*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1035*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1036*49ef7e06SGarrett D'Amore 	uint16_t magic;
1037*49ef7e06SGarrett D'Amore 
1038*49ef7e06SGarrett D'Amore 	/*
1039*49ef7e06SGarrett D'Amore 	 * man timeout(9f) states that this code should adhere to the
1040*49ef7e06SGarrett D'Amore 	 * same requirements as a softirq handler - DO NOT BLOCK
1041*49ef7e06SGarrett D'Amore 	 */
1042*49ef7e06SGarrett D'Amore 
1043*49ef7e06SGarrett D'Amore 	/*
1044*49ef7e06SGarrett D'Amore 	 * Post an event to the event queue to cause the free packet pool to be
1045*49ef7e06SGarrett D'Amore 	 * trimmed if it is oversize.
1046*49ef7e06SGarrett D'Amore 	 */
1047*49ef7e06SGarrett D'Amore 	magic = SFXGE_MAGIC_RX_QFPP_TRIM | index;
1048*49ef7e06SGarrett D'Amore 
1049*49ef7e06SGarrett D'Amore #if defined(DEBUG)
1050*49ef7e06SGarrett D'Amore 	/* This is guaranteed due to the start/stop order of rx and ev */
1051*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTED);
1052*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_STARTED);
1053*49ef7e06SGarrett D'Amore #else
1054*49ef7e06SGarrett D'Amore 	/*
1055*49ef7e06SGarrett D'Amore 	 * Bug22691 WORKAROUND:
1056*49ef7e06SGarrett D'Amore 	 * This handler has been observed in the field to be invoked for a
1057*49ef7e06SGarrett D'Amore 	 * queue in the INITIALIZED state, which should never happen.
1058*49ef7e06SGarrett D'Amore 	 * Until the mechanism for this is properly understood, add defensive
1059*49ef7e06SGarrett D'Amore 	 * checks.
1060*49ef7e06SGarrett D'Amore 	 */
1061*49ef7e06SGarrett D'Amore 	if ((sep->se_state != SFXGE_EVQ_STARTED) ||
1062*49ef7e06SGarrett D'Amore 	    (srp->sr_state != SFXGE_RXQ_STARTED) ||
1063*49ef7e06SGarrett D'Amore 	    (!sep->se_eep)) {
1064*49ef7e06SGarrett D'Amore 		dev_err(sp->s_dip, CE_WARN, SFXGE_CMN_ERR
1065*49ef7e06SGarrett D'Amore 		    "RXQ[%d] bad state in sfxge_rx_qpoll %d %d %p",
1066*49ef7e06SGarrett D'Amore 		    index, sep->se_state, srp->sr_state, sep->se_eep);
1067*49ef7e06SGarrett D'Amore 		return;
1068*49ef7e06SGarrett D'Amore 	}
1069*49ef7e06SGarrett D'Amore #endif
1070*49ef7e06SGarrett D'Amore 	efx_ev_qpost(sep->se_eep, magic);
1071*49ef7e06SGarrett D'Amore 
1072*49ef7e06SGarrett D'Amore 	srp->sr_tid = timeout(sfxge_rx_qpoll, srp,
1073*49ef7e06SGarrett D'Amore 	    drv_usectohz(sp->s_rxq_poll_usec));
1074*49ef7e06SGarrett D'Amore }
1075*49ef7e06SGarrett D'Amore 
1076*49ef7e06SGarrett D'Amore static void
sfxge_rx_qpoll_start(sfxge_rxq_t * srp)1077*49ef7e06SGarrett D'Amore sfxge_rx_qpoll_start(sfxge_rxq_t *srp)
1078*49ef7e06SGarrett D'Amore {
1079*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1080*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1081*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1082*49ef7e06SGarrett D'Amore 
1083*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
1084*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_STARTED);
1085*49ef7e06SGarrett D'Amore 
1086*49ef7e06SGarrett D'Amore 	/* Schedule a poll */
1087*49ef7e06SGarrett D'Amore 	ASSERT3P(srp->sr_tid, ==, 0);
1088*49ef7e06SGarrett D'Amore 	srp->sr_tid = timeout(sfxge_rx_qpoll, srp, 0);
1089*49ef7e06SGarrett D'Amore }
1090*49ef7e06SGarrett D'Amore 
1091*49ef7e06SGarrett D'Amore static void
sfxge_rx_qpoll_stop(sfxge_rxq_t * srp)1092*49ef7e06SGarrett D'Amore sfxge_rx_qpoll_stop(sfxge_rxq_t *srp)
1093*49ef7e06SGarrett D'Amore {
1094*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1095*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1096*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1097*49ef7e06SGarrett D'Amore 	timeout_id_t tid;
1098*49ef7e06SGarrett D'Amore 
1099*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
1100*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_STARTED);
1101*49ef7e06SGarrett D'Amore 
1102*49ef7e06SGarrett D'Amore 	/*
1103*49ef7e06SGarrett D'Amore 	 * Cancel the qpoll timer. Care is needed as this function
1104*49ef7e06SGarrett D'Amore 	 * can race with sfxge_rx_qpoll() for timeout id updates.
1105*49ef7e06SGarrett D'Amore 	 *
1106*49ef7e06SGarrett D'Amore 	 * Do not hold locks used by any timeout(9f) handlers across
1107*49ef7e06SGarrett D'Amore 	 * calls to untimeout(9f) as this will deadlock.
1108*49ef7e06SGarrett D'Amore 	 */
1109*49ef7e06SGarrett D'Amore 	tid = 0;
1110*49ef7e06SGarrett D'Amore 	while ((srp->sr_tid != 0) && (srp->sr_tid != tid)) {
1111*49ef7e06SGarrett D'Amore 		tid = srp->sr_tid;
1112*49ef7e06SGarrett D'Amore 		(void) untimeout(tid);
1113*49ef7e06SGarrett D'Amore 	}
1114*49ef7e06SGarrett D'Amore 	srp->sr_tid = 0;
1115*49ef7e06SGarrett D'Amore }
1116*49ef7e06SGarrett D'Amore 
1117*49ef7e06SGarrett D'Amore static int
sfxge_rx_kstat_update(kstat_t * ksp,int rw)1118*49ef7e06SGarrett D'Amore sfxge_rx_kstat_update(kstat_t *ksp, int rw)
1119*49ef7e06SGarrett D'Amore {
1120*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = ksp->ks_private;
1121*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1122*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1123*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1124*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
1125*49ef7e06SGarrett D'Amore 	int rc;
1126*49ef7e06SGarrett D'Amore 
1127*49ef7e06SGarrett D'Amore 	if (rw != KSTAT_READ) {
1128*49ef7e06SGarrett D'Amore 		rc = EACCES;
1129*49ef7e06SGarrett D'Amore 		goto fail1;
1130*49ef7e06SGarrett D'Amore 	}
1131*49ef7e06SGarrett D'Amore 
1132*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
1133*49ef7e06SGarrett D'Amore 	if (srp->sr_state != SFXGE_RXQ_STARTED)
1134*49ef7e06SGarrett D'Amore 		goto done;
1135*49ef7e06SGarrett D'Amore 
1136*49ef7e06SGarrett D'Amore 	knp = ksp->ks_data;
1137*49ef7e06SGarrett D'Amore 	/* NB pointer post-increment below */
1138*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_rx_pkt_mem_limit;
1139*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_kcache_alloc_nomem;
1140*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_dma_alloc_nomem;
1141*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_dma_alloc_fail;
1142*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_dma_bind_nomem;
1143*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_dma_bind_fail;
1144*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_desballoc_fail;
1145*49ef7e06SGarrett D'Amore 	knp++->value.ui32 = srp->sr_kstat.srk_rxq_empty_discard;
1146*49ef7e06SGarrett D'Amore 
1147*49ef7e06SGarrett D'Amore done:
1148*49ef7e06SGarrett D'Amore 	return (0);
1149*49ef7e06SGarrett D'Amore 
1150*49ef7e06SGarrett D'Amore fail1:
1151*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1152*49ef7e06SGarrett D'Amore 
1153*49ef7e06SGarrett D'Amore 	return (rc);
1154*49ef7e06SGarrett D'Amore }
1155*49ef7e06SGarrett D'Amore 
1156*49ef7e06SGarrett D'Amore static int
sfxge_rx_kstat_init(sfxge_rxq_t * srp)1157*49ef7e06SGarrett D'Amore sfxge_rx_kstat_init(sfxge_rxq_t *srp)
1158*49ef7e06SGarrett D'Amore {
1159*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1160*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1161*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1162*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
1163*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
1164*49ef7e06SGarrett D'Amore 	kstat_t *ksp;
1165*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
1166*49ef7e06SGarrett D'Amore 	int rc;
1167*49ef7e06SGarrett D'Amore 
1168*49ef7e06SGarrett D'Amore 	/* Create the set */
1169*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s_rxq%04d",
1170*49ef7e06SGarrett D'Amore 	    ddi_driver_name(dip), index);
1171*49ef7e06SGarrett D'Amore 
1172*49ef7e06SGarrett D'Amore 	if ((ksp = kstat_create((char *)ddi_driver_name(dip),
1173*49ef7e06SGarrett D'Amore 	    ddi_get_instance(dip), name, "rxq", KSTAT_TYPE_NAMED,
1174*49ef7e06SGarrett D'Amore 	    SFXGE_RX_NSTATS, 0)) == NULL) {
1175*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
1176*49ef7e06SGarrett D'Amore 		goto fail1;
1177*49ef7e06SGarrett D'Amore 	}
1178*49ef7e06SGarrett D'Amore 
1179*49ef7e06SGarrett D'Amore 	srp->sr_ksp = ksp;
1180*49ef7e06SGarrett D'Amore 
1181*49ef7e06SGarrett D'Amore 	ksp->ks_update = sfxge_rx_kstat_update;
1182*49ef7e06SGarrett D'Amore 	ksp->ks_private = srp;
1183*49ef7e06SGarrett D'Amore 	ksp->ks_lock = &(sep->se_lock);
1184*49ef7e06SGarrett D'Amore 
1185*49ef7e06SGarrett D'Amore 	/* Initialise the named stats */
1186*49ef7e06SGarrett D'Amore 	knp = ksp->ks_data;
1187*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "rx_pkt_mem_limit", KSTAT_DATA_UINT32);
1188*49ef7e06SGarrett D'Amore 	knp++;
1189*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "kcache_alloc_nomem", KSTAT_DATA_UINT32);
1190*49ef7e06SGarrett D'Amore 	knp++;
1191*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dma_alloc_nomem", KSTAT_DATA_UINT32);
1192*49ef7e06SGarrett D'Amore 	knp++;
1193*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dma_alloc_fail", KSTAT_DATA_UINT32);
1194*49ef7e06SGarrett D'Amore 	knp++;
1195*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dma_bind_nomem", KSTAT_DATA_UINT32);
1196*49ef7e06SGarrett D'Amore 	knp++;
1197*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "dma_bind_fail", KSTAT_DATA_UINT32);
1198*49ef7e06SGarrett D'Amore 	knp++;
1199*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "desballoc_fail", KSTAT_DATA_UINT32);
1200*49ef7e06SGarrett D'Amore 	knp++;
1201*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "rxq_empty_discard", KSTAT_DATA_UINT32);
1202*49ef7e06SGarrett D'Amore 
1203*49ef7e06SGarrett D'Amore 	kstat_install(ksp);
1204*49ef7e06SGarrett D'Amore 	return (0);
1205*49ef7e06SGarrett D'Amore 
1206*49ef7e06SGarrett D'Amore fail1:
1207*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1208*49ef7e06SGarrett D'Amore 
1209*49ef7e06SGarrett D'Amore 	return (rc);
1210*49ef7e06SGarrett D'Amore }
1211*49ef7e06SGarrett D'Amore 
1212*49ef7e06SGarrett D'Amore static int
sfxge_rx_qinit(sfxge_t * sp,unsigned int index)1213*49ef7e06SGarrett D'Amore sfxge_rx_qinit(sfxge_t *sp, unsigned int index)
1214*49ef7e06SGarrett D'Amore {
1215*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp;
1216*49ef7e06SGarrett D'Amore 	int rc;
1217*49ef7e06SGarrett D'Amore 
1218*49ef7e06SGarrett D'Amore 	ASSERT3U(index, <, SFXGE_RX_SCALE_MAX);
1219*49ef7e06SGarrett D'Amore 
1220*49ef7e06SGarrett D'Amore 	if ((srp = kmem_cache_alloc(sp->s_rqc, KM_SLEEP)) == NULL) {
1221*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
1222*49ef7e06SGarrett D'Amore 		goto fail1;
1223*49ef7e06SGarrett D'Amore 	}
1224*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_UNINITIALIZED);
1225*49ef7e06SGarrett D'Amore 
1226*49ef7e06SGarrett D'Amore 	srp->sr_index = index;
1227*49ef7e06SGarrett D'Amore 	sp->s_srp[index] = srp;
1228*49ef7e06SGarrett D'Amore 
1229*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_rx_kstat_init(srp)) != 0)
1230*49ef7e06SGarrett D'Amore 		goto fail2;
1231*49ef7e06SGarrett D'Amore 
1232*49ef7e06SGarrett D'Amore 	srp->sr_state = SFXGE_RXQ_INITIALIZED;
1233*49ef7e06SGarrett D'Amore 
1234*49ef7e06SGarrett D'Amore 	return (0);
1235*49ef7e06SGarrett D'Amore 
1236*49ef7e06SGarrett D'Amore fail2:
1237*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1238*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_rqc, srp);
1239*49ef7e06SGarrett D'Amore 
1240*49ef7e06SGarrett D'Amore fail1:
1241*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
1242*49ef7e06SGarrett D'Amore 
1243*49ef7e06SGarrett D'Amore 	return (rc);
1244*49ef7e06SGarrett D'Amore }
1245*49ef7e06SGarrett D'Amore 
1246*49ef7e06SGarrett D'Amore static int
sfxge_rx_qstart(sfxge_t * sp,unsigned int index)1247*49ef7e06SGarrett D'Amore sfxge_rx_qstart(sfxge_t *sp, unsigned int index)
1248*49ef7e06SGarrett D'Amore {
1249*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1250*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp;
1251*49ef7e06SGarrett D'Amore 	efsys_mem_t *esmp;
1252*49ef7e06SGarrett D'Amore 	efx_nic_t *enp;
1253*49ef7e06SGarrett D'Amore 	unsigned int level;
1254*49ef7e06SGarrett D'Amore 	int rc;
1255*49ef7e06SGarrett D'Amore 
1256*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
1257*49ef7e06SGarrett D'Amore 	srp = sp->s_srp[index];
1258*49ef7e06SGarrett D'Amore 	enp = sp->s_enp;
1259*49ef7e06SGarrett D'Amore 	esmp = &(srp->sr_mem);
1260*49ef7e06SGarrett D'Amore 
1261*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_INITIALIZED);
1262*49ef7e06SGarrett D'Amore 	ASSERT3U(sep->se_state, ==, SFXGE_EVQ_STARTED);
1263*49ef7e06SGarrett D'Amore 
1264*49ef7e06SGarrett D'Amore 	/* Zero the memory */
1265*49ef7e06SGarrett D'Amore 	bzero(esmp->esm_base, EFX_RXQ_SIZE(sp->s_rxq_size));
1266*49ef7e06SGarrett D'Amore 
1267*49ef7e06SGarrett D'Amore 	/* Program the buffer table */
1268*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_sram_buf_tbl_set(sp, srp->sr_id, esmp,
1269*49ef7e06SGarrett D'Amore 	    EFX_RXQ_NBUFS(sp->s_rxq_size))) != 0)
1270*49ef7e06SGarrett D'Amore 		goto fail1;
1271*49ef7e06SGarrett D'Amore 
1272*49ef7e06SGarrett D'Amore 	/* Create the receive queue */
1273*49ef7e06SGarrett D'Amore 	if ((rc = efx_rx_qcreate(enp, index, index, EFX_RXQ_TYPE_DEFAULT,
1274*49ef7e06SGarrett D'Amore 	    esmp, sp->s_rxq_size, srp->sr_id, sep->se_eep, &(srp->sr_erp)))
1275*49ef7e06SGarrett D'Amore 	    != 0)
1276*49ef7e06SGarrett D'Amore 		goto fail2;
1277*49ef7e06SGarrett D'Amore 
1278*49ef7e06SGarrett D'Amore 	/* Enable the receive queue */
1279*49ef7e06SGarrett D'Amore 	efx_rx_qenable(srp->sr_erp);
1280*49ef7e06SGarrett D'Amore 
1281*49ef7e06SGarrett D'Amore 	/* Set the water marks */
1282*49ef7e06SGarrett D'Amore 	srp->sr_hiwat = EFX_RXQ_LIMIT(sp->s_rxq_size) * 9 / 10;
1283*49ef7e06SGarrett D'Amore 	srp->sr_lowat = srp->sr_hiwat / 2;
1284*49ef7e06SGarrett D'Amore 
1285*49ef7e06SGarrett D'Amore 	srp->sr_state = SFXGE_RXQ_STARTED;
1286*49ef7e06SGarrett D'Amore 	srp->sr_flush = SFXGE_FLUSH_INACTIVE;
1287*49ef7e06SGarrett D'Amore 
1288*49ef7e06SGarrett D'Amore 	sfxge_rx_qpoll_start(srp);
1289*49ef7e06SGarrett D'Amore 
1290*49ef7e06SGarrett D'Amore 	/* Try to fill the queue from the pool */
1291*49ef7e06SGarrett D'Amore 	sfxge_rx_qrefill(srp, EFX_RXQ_LIMIT(sp->s_rxq_size));
1292*49ef7e06SGarrett D'Amore 
1293*49ef7e06SGarrett D'Amore 	/*
1294*49ef7e06SGarrett D'Amore 	 * If there were insufficient buffers in the pool to reach the at
1295*49ef7e06SGarrett D'Amore 	 * least a batch then allocate some.
1296*49ef7e06SGarrett D'Amore 	 */
1297*49ef7e06SGarrett D'Amore 	level = srp->sr_added - srp->sr_completed;
1298*49ef7e06SGarrett D'Amore 	if (level < SFXGE_RX_BATCH)
1299*49ef7e06SGarrett D'Amore 		sfxge_rx_qfill(srp, SFXGE_RX_BATCH);
1300*49ef7e06SGarrett D'Amore 
1301*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
1302*49ef7e06SGarrett D'Amore 
1303*49ef7e06SGarrett D'Amore 	return (0);
1304*49ef7e06SGarrett D'Amore 
1305*49ef7e06SGarrett D'Amore fail2:
1306*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
1307*49ef7e06SGarrett D'Amore 
1308*49ef7e06SGarrett D'Amore 	/* Clear entries from the buffer table */
1309*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_clear(sp, srp->sr_id,
1310*49ef7e06SGarrett D'Amore 	    EFX_RXQ_NBUFS(sp->s_rxq_size));
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 	mutex_exit(&(sep->se_lock));
1316*49ef7e06SGarrett D'Amore 
1317*49ef7e06SGarrett D'Amore 	return (rc);
1318*49ef7e06SGarrett D'Amore }
1319*49ef7e06SGarrett D'Amore 
1320*49ef7e06SGarrett D'Amore static void
sfxge_rx_qflow_complete(sfxge_rxq_t * srp,sfxge_rx_flow_t * srfp)1321*49ef7e06SGarrett D'Amore sfxge_rx_qflow_complete(sfxge_rxq_t *srp, sfxge_rx_flow_t *srfp)
1322*49ef7e06SGarrett D'Amore {
1323*49ef7e06SGarrett D'Amore 	mblk_t *mp;
1324*49ef7e06SGarrett D'Amore 	struct ether_header *etherhp;
1325*49ef7e06SGarrett D'Amore 	struct ip *iphp;
1326*49ef7e06SGarrett D'Amore 	struct tcphdr *thp;
1327*49ef7e06SGarrett D'Amore 
1328*49ef7e06SGarrett D'Amore 	if (srfp->srf_mp == NULL)
1329*49ef7e06SGarrett D'Amore 		return;
1330*49ef7e06SGarrett D'Amore 
1331*49ef7e06SGarrett D'Amore 	mp = srfp->srf_mp;
1332*49ef7e06SGarrett D'Amore 	etherhp = srfp->srf_etherhp;
1333*49ef7e06SGarrett D'Amore 	iphp = srfp->srf_iphp;
1334*49ef7e06SGarrett D'Amore 	thp = srfp->srf_last_thp;
1335*49ef7e06SGarrett D'Amore 
1336*49ef7e06SGarrett D'Amore 	ASSERT3U(((etherhp->ether_type == htons(ETHERTYPE_VLAN)) ?
1337*49ef7e06SGarrett D'Amore 	    sizeof (struct ether_vlan_header) :
1338*49ef7e06SGarrett D'Amore 	    sizeof (struct ether_header)) +
1339*49ef7e06SGarrett D'Amore 	    srfp->srf_len, ==, msgdsize(mp));
1340*49ef7e06SGarrett D'Amore 
1341*49ef7e06SGarrett D'Amore 	ASSERT3U(srfp->srf_len & 0xffff, ==, srfp->srf_len);
1342*49ef7e06SGarrett D'Amore 	iphp->ip_len = htons(srfp->srf_len);
1343*49ef7e06SGarrett D'Amore 
1344*49ef7e06SGarrett D'Amore 	srfp->srf_first_thp->th_ack = thp->th_ack;
1345*49ef7e06SGarrett D'Amore 	srfp->srf_first_thp->th_win = thp->th_win;
1346*49ef7e06SGarrett D'Amore 	srfp->srf_first_thp->th_flags = thp->th_flags;
1347*49ef7e06SGarrett D'Amore 
1348*49ef7e06SGarrett D'Amore 	DTRACE_PROBE2(flow_complete, uint32_t, srfp->srf_tag,
1349*49ef7e06SGarrett D'Amore 	    size_t, srfp->srf_len);
1350*49ef7e06SGarrett D'Amore 
1351*49ef7e06SGarrett D'Amore 	srfp->srf_mp = NULL;
1352*49ef7e06SGarrett D'Amore 	srfp->srf_len = 0;
1353*49ef7e06SGarrett D'Amore 
1354*49ef7e06SGarrett D'Amore 	ASSERT(mp->b_next == NULL);
1355*49ef7e06SGarrett D'Amore 	*(srp->sr_mpp) = mp;
1356*49ef7e06SGarrett D'Amore 	srp->sr_mpp = &(mp->b_next);
1357*49ef7e06SGarrett D'Amore }
1358*49ef7e06SGarrett D'Amore 
1359*49ef7e06SGarrett D'Amore static boolean_t
sfxge_rx_qflow_add(sfxge_rxq_t * srp,sfxge_rx_flow_t * srfp,sfxge_rx_packet_t * srpp,clock_t now)1360*49ef7e06SGarrett D'Amore sfxge_rx_qflow_add(sfxge_rxq_t *srp, sfxge_rx_flow_t *srfp,
1361*49ef7e06SGarrett D'Amore     sfxge_rx_packet_t *srpp, clock_t now)
1362*49ef7e06SGarrett D'Amore {
1363*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1364*49ef7e06SGarrett D'Amore 	struct ether_header *etherhp = srpp->srp_etherhp;
1365*49ef7e06SGarrett D'Amore 	struct ip *iphp = srpp->srp_iphp;
1366*49ef7e06SGarrett D'Amore 	struct tcphdr *thp = srpp->srp_thp;
1367*49ef7e06SGarrett D'Amore 	size_t off = srpp->srp_off;
1368*49ef7e06SGarrett D'Amore 	size_t size = (size_t)(srpp->srp_size);
1369*49ef7e06SGarrett D'Amore 	mblk_t *mp = srpp->srp_mp;
1370*49ef7e06SGarrett D'Amore 	uint32_t seq;
1371*49ef7e06SGarrett D'Amore 	unsigned int shift;
1372*49ef7e06SGarrett D'Amore 
1373*49ef7e06SGarrett D'Amore 	ASSERT3U(MBLKL(mp), ==, off + size);
1374*49ef7e06SGarrett D'Amore 	ASSERT3U(DB_CKSUMFLAGS(mp), ==,
1375*49ef7e06SGarrett D'Amore 	    HCK_FULLCKSUM | HCK_FULLCKSUM_OK | HCK_IPV4_HDRCKSUM);
1376*49ef7e06SGarrett D'Amore 
1377*49ef7e06SGarrett D'Amore 	seq = htonl(thp->th_seq);
1378*49ef7e06SGarrett D'Amore 
1379*49ef7e06SGarrett D'Amore 	/*
1380*49ef7e06SGarrett D'Amore 	 * If the time between this segment and the last is greater than RTO
1381*49ef7e06SGarrett D'Amore 	 * then consider this a new flow.
1382*49ef7e06SGarrett D'Amore 	 */
1383*49ef7e06SGarrett D'Amore 	if (now - srfp->srf_lbolt > srp->sr_rto) {
1384*49ef7e06SGarrett D'Amore 		srfp->srf_count = 1;
1385*49ef7e06SGarrett D'Amore 		srfp->srf_seq = seq + size;
1386*49ef7e06SGarrett D'Amore 
1387*49ef7e06SGarrett D'Amore 		goto fail1;
1388*49ef7e06SGarrett D'Amore 	}
1389*49ef7e06SGarrett D'Amore 
1390*49ef7e06SGarrett D'Amore 	if (seq != srfp->srf_seq) {
1391*49ef7e06SGarrett D'Amore 		if (srfp->srf_count > SFXGE_SLOW_START)
1392*49ef7e06SGarrett D'Amore 			srfp->srf_count = SFXGE_SLOW_START;
1393*49ef7e06SGarrett D'Amore 
1394*49ef7e06SGarrett D'Amore 		srfp->srf_count >>= 1;
1395*49ef7e06SGarrett D'Amore 
1396*49ef7e06SGarrett D'Amore 		srfp->srf_count++;
1397*49ef7e06SGarrett D'Amore 		srfp->srf_seq = seq + size;
1398*49ef7e06SGarrett D'Amore 
1399*49ef7e06SGarrett D'Amore 		goto fail2;
1400*49ef7e06SGarrett D'Amore 	}
1401*49ef7e06SGarrett D'Amore 
1402*49ef7e06SGarrett D'Amore 	/* Update the in-order segment count and sequence number */
1403*49ef7e06SGarrett D'Amore 	srfp->srf_count++;
1404*49ef7e06SGarrett D'Amore 	srfp->srf_seq = seq + size;
1405*49ef7e06SGarrett D'Amore 
1406*49ef7e06SGarrett D'Amore 	/* Don't merge across pure ACK, URG, SYN or RST segments */
1407*49ef7e06SGarrett D'Amore 	if (size == 0 || thp->th_flags & (TH_URG | TH_SYN | TH_RST) ||
1408*49ef7e06SGarrett D'Amore 	    thp->th_urp != 0)
1409*49ef7e06SGarrett D'Amore 		goto fail3;
1410*49ef7e06SGarrett D'Amore 
1411*49ef7e06SGarrett D'Amore 	/*
1412*49ef7e06SGarrett D'Amore 	 * If the in-order segment count has not yet reached the slow-start
1413*49ef7e06SGarrett D'Amore 	 * threshold then we cannot coalesce.
1414*49ef7e06SGarrett D'Amore 	 */
1415*49ef7e06SGarrett D'Amore 	if (srfp->srf_count < SFXGE_SLOW_START)
1416*49ef7e06SGarrett D'Amore 		goto fail4;
1417*49ef7e06SGarrett D'Amore 
1418*49ef7e06SGarrett D'Amore 	/* Scale up the packet size from 4k (the maximum being 64k) */
1419*49ef7e06SGarrett D'Amore 	ASSERT3U(srfp->srf_count, >=, SFXGE_SLOW_START);
1420*49ef7e06SGarrett D'Amore 	shift = MIN(srfp->srf_count - SFXGE_SLOW_START + 12, 16);
1421*49ef7e06SGarrett D'Amore 	if (srfp->srf_len + size >= (1 << shift))
1422*49ef7e06SGarrett D'Amore 		sfxge_rx_qflow_complete(srp, srfp);
1423*49ef7e06SGarrett D'Amore 
1424*49ef7e06SGarrett D'Amore 	ASSERT(mp->b_cont == NULL);
1425*49ef7e06SGarrett D'Amore 
1426*49ef7e06SGarrett D'Amore 	if (srfp->srf_mp == NULL) {
1427*49ef7e06SGarrett D'Amore 		/* First packet in this flow */
1428*49ef7e06SGarrett D'Amore 		srfp->srf_etherhp = etherhp;
1429*49ef7e06SGarrett D'Amore 		srfp->srf_iphp = iphp;
1430*49ef7e06SGarrett D'Amore 		srfp->srf_first_thp = srfp->srf_last_thp = thp;
1431*49ef7e06SGarrett D'Amore 
1432*49ef7e06SGarrett D'Amore 		ASSERT3P(mp->b_cont, ==, NULL);
1433*49ef7e06SGarrett D'Amore 		srfp->srf_mp = mp;
1434*49ef7e06SGarrett D'Amore 		srfp->srf_mpp = &(mp->b_cont);
1435*49ef7e06SGarrett D'Amore 
1436*49ef7e06SGarrett D'Amore 		srfp->srf_len = ntohs(iphp->ip_len);
1437*49ef7e06SGarrett D'Amore 
1438*49ef7e06SGarrett D'Amore 		/*
1439*49ef7e06SGarrett D'Amore 		 * If the flow is not already in the list of occupied flows then
1440*49ef7e06SGarrett D'Amore 		 * add it.
1441*49ef7e06SGarrett D'Amore 		 */
1442*49ef7e06SGarrett D'Amore 		if (srfp->srf_next == NULL &&
1443*49ef7e06SGarrett D'Amore 		    srp->sr_srfpp != &(srfp->srf_next)) {
1444*49ef7e06SGarrett D'Amore 			*(srp->sr_srfpp) = srfp;
1445*49ef7e06SGarrett D'Amore 			srp->sr_srfpp = &(srfp->srf_next);
1446*49ef7e06SGarrett D'Amore 		}
1447*49ef7e06SGarrett D'Amore 	} else {
1448*49ef7e06SGarrett D'Amore 		/* Later packet in this flow - skip TCP header */
1449*49ef7e06SGarrett D'Amore 		srfp->srf_last_thp = thp;
1450*49ef7e06SGarrett D'Amore 
1451*49ef7e06SGarrett D'Amore 		mp->b_rptr += off;
1452*49ef7e06SGarrett D'Amore 		ASSERT3U(MBLKL(mp), ==, size);
1453*49ef7e06SGarrett D'Amore 
1454*49ef7e06SGarrett D'Amore 		ASSERT3P(mp->b_cont, ==, NULL);
1455*49ef7e06SGarrett D'Amore 		*(srfp->srf_mpp) = mp;
1456*49ef7e06SGarrett D'Amore 		srfp->srf_mpp = &(mp->b_cont);
1457*49ef7e06SGarrett D'Amore 
1458*49ef7e06SGarrett D'Amore 		srfp->srf_len += size;
1459*49ef7e06SGarrett D'Amore 
1460*49ef7e06SGarrett D'Amore 		ASSERT(srfp->srf_next != NULL ||
1461*49ef7e06SGarrett D'Amore 		    srp->sr_srfpp == &(srfp->srf_next));
1462*49ef7e06SGarrett D'Amore 	}
1463*49ef7e06SGarrett D'Amore 
1464*49ef7e06SGarrett D'Amore 	DTRACE_PROBE2(flow_add, uint32_t, srfp->srf_tag, size_t, size);
1465*49ef7e06SGarrett D'Amore 
1466*49ef7e06SGarrett D'Amore 	/*
1467*49ef7e06SGarrett D'Amore 	 * Try to align coalesced segments on push boundaries, unless they
1468*49ef7e06SGarrett D'Amore 	 * are too frequent.
1469*49ef7e06SGarrett D'Amore 	 */
1470*49ef7e06SGarrett D'Amore 	if (sp->s_rx_coalesce_mode == SFXGE_RX_COALESCE_ALLOW_PUSH &&
1471*49ef7e06SGarrett D'Amore 	    thp->th_flags & TH_PUSH)
1472*49ef7e06SGarrett D'Amore 		sfxge_rx_qflow_complete(srp, srfp);
1473*49ef7e06SGarrett D'Amore 
1474*49ef7e06SGarrett D'Amore 	srfp->srf_lbolt = now;
1475*49ef7e06SGarrett D'Amore 	return (B_TRUE);
1476*49ef7e06SGarrett D'Amore 
1477*49ef7e06SGarrett D'Amore fail4:
1478*49ef7e06SGarrett D'Amore fail3:
1479*49ef7e06SGarrett D'Amore fail2:
1480*49ef7e06SGarrett D'Amore fail1:
1481*49ef7e06SGarrett D'Amore 	sfxge_rx_qflow_complete(srp, srfp);
1482*49ef7e06SGarrett D'Amore 
1483*49ef7e06SGarrett D'Amore 	srfp->srf_lbolt = now;
1484*49ef7e06SGarrett D'Amore 	return (B_FALSE);
1485*49ef7e06SGarrett D'Amore }
1486*49ef7e06SGarrett D'Amore 
1487*49ef7e06SGarrett D'Amore void
sfxge_rx_qpacket_coalesce(sfxge_rxq_t * srp)1488*49ef7e06SGarrett D'Amore sfxge_rx_qpacket_coalesce(sfxge_rxq_t *srp)
1489*49ef7e06SGarrett D'Amore {
1490*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1491*49ef7e06SGarrett D'Amore 	clock_t now;
1492*49ef7e06SGarrett D'Amore 	mblk_t *mp;
1493*49ef7e06SGarrett D'Amore 	sfxge_rx_flow_t *srfp;
1494*49ef7e06SGarrett D'Amore 
1495*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_rx_coalesce_mode != SFXGE_RX_COALESCE_OFF);
1496*49ef7e06SGarrett D'Amore 
1497*49ef7e06SGarrett D'Amore 	now = ddi_get_lbolt();
1498*49ef7e06SGarrett D'Amore 
1499*49ef7e06SGarrett D'Amore 	mp = srp->sr_mp;
1500*49ef7e06SGarrett D'Amore 
1501*49ef7e06SGarrett D'Amore 	srp->sr_mp = NULL;
1502*49ef7e06SGarrett D'Amore 	srp->sr_mpp = &(srp->sr_mp);
1503*49ef7e06SGarrett D'Amore 
1504*49ef7e06SGarrett D'Amore 	/* Start with the last flow to be appended to */
1505*49ef7e06SGarrett D'Amore 	srfp = *(srp->sr_srfpp);
1506*49ef7e06SGarrett D'Amore 
1507*49ef7e06SGarrett D'Amore 	while (mp != NULL) {
1508*49ef7e06SGarrett D'Amore 		frtn_t *freep;
1509*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
1510*49ef7e06SGarrett D'Amore 		struct ether_header *etherhp;
1511*49ef7e06SGarrett D'Amore 		struct ip *iphp;
1512*49ef7e06SGarrett D'Amore 		struct tcphdr *thp;
1513*49ef7e06SGarrett D'Amore 		size_t off;
1514*49ef7e06SGarrett D'Amore 		size_t size;
1515*49ef7e06SGarrett D'Amore 		uint16_t ether_tci;
1516*49ef7e06SGarrett D'Amore 		uint32_t hash;
1517*49ef7e06SGarrett D'Amore 		uint32_t tag;
1518*49ef7e06SGarrett D'Amore 		mblk_t *next;
1519*49ef7e06SGarrett D'Amore 		sfxge_packet_type_t pkt_type;
1520*49ef7e06SGarrett D'Amore 		uint16_t sport, dport;
1521*49ef7e06SGarrett D'Amore 
1522*49ef7e06SGarrett D'Amore 		next = mp->b_next;
1523*49ef7e06SGarrett D'Amore 		mp->b_next = NULL;
1524*49ef7e06SGarrett D'Amore 
1525*49ef7e06SGarrett D'Amore 		if (next != NULL)
1526*49ef7e06SGarrett D'Amore 			prefetch_read_many(next);
1527*49ef7e06SGarrett D'Amore 
1528*49ef7e06SGarrett D'Amore 		freep = DB_FRTNP(mp);
1529*49ef7e06SGarrett D'Amore 		/*LINTED*/
1530*49ef7e06SGarrett D'Amore 		srpp = (sfxge_rx_packet_t *)(freep->free_arg);
1531*49ef7e06SGarrett D'Amore 		ASSERT3P(srpp->srp_mp, ==, mp);
1532*49ef7e06SGarrett D'Amore 
1533*49ef7e06SGarrett D'Amore 		/* If the packet is not TCP then we cannot coalesce it */
1534*49ef7e06SGarrett D'Amore 		if (~(srpp->srp_flags) & EFX_PKT_TCP)
1535*49ef7e06SGarrett D'Amore 			goto reject;
1536*49ef7e06SGarrett D'Amore 
1537*49ef7e06SGarrett D'Amore 		/*
1538*49ef7e06SGarrett D'Amore 		 * If the packet is not fully checksummed then we cannot
1539*49ef7e06SGarrett D'Amore 		 * coalesce it.
1540*49ef7e06SGarrett D'Amore 		 */
1541*49ef7e06SGarrett D'Amore 		if (~(srpp->srp_flags) & (EFX_CKSUM_TCPUDP | EFX_CKSUM_IPV4))
1542*49ef7e06SGarrett D'Amore 			goto reject;
1543*49ef7e06SGarrett D'Amore 
1544*49ef7e06SGarrett D'Amore 		/* Parse the TCP header */
1545*49ef7e06SGarrett D'Amore 		pkt_type = sfxge_pkthdr_parse(mp, &etherhp, &iphp, &thp, &off,
1546*49ef7e06SGarrett D'Amore 		    &size, &sport, &dport);
1547*49ef7e06SGarrett D'Amore 		ASSERT(pkt_type == SFXGE_PACKET_TYPE_IPV4_TCP);
1548*49ef7e06SGarrett D'Amore 		ASSERT(etherhp != NULL);
1549*49ef7e06SGarrett D'Amore 		ASSERT(iphp != NULL);
1550*49ef7e06SGarrett D'Amore 		ASSERT(thp != NULL);
1551*49ef7e06SGarrett D'Amore 		ASSERT(off != 0);
1552*49ef7e06SGarrett D'Amore 
1553*49ef7e06SGarrett D'Amore 		if ((iphp->ip_off & ~htons(IP_DF)) != 0)
1554*49ef7e06SGarrett D'Amore 			goto reject;
1555*49ef7e06SGarrett D'Amore 
1556*49ef7e06SGarrett D'Amore 		if (etherhp->ether_type == htons(ETHERTYPE_VLAN)) {
1557*49ef7e06SGarrett D'Amore 			struct ether_vlan_header *ethervhp;
1558*49ef7e06SGarrett D'Amore 
1559*49ef7e06SGarrett D'Amore 			ethervhp = (struct ether_vlan_header *)etherhp;
1560*49ef7e06SGarrett D'Amore 			ether_tci = ethervhp->ether_tci;
1561*49ef7e06SGarrett D'Amore 		} else {
1562*49ef7e06SGarrett D'Amore 			ether_tci = 0;
1563*49ef7e06SGarrett D'Amore 		}
1564*49ef7e06SGarrett D'Amore 
1565*49ef7e06SGarrett D'Amore 		/*
1566*49ef7e06SGarrett D'Amore 		 * Make sure any minimum length padding is stripped
1567*49ef7e06SGarrett D'Amore 		 * before we try to add the packet to a flow.
1568*49ef7e06SGarrett D'Amore 		 */
1569*49ef7e06SGarrett D'Amore 		ASSERT3U(sp->s_rx_prefix_size + MBLKL(mp), ==,
1570*49ef7e06SGarrett D'Amore 		    (size_t)(srpp->srp_size));
1571*49ef7e06SGarrett D'Amore 		ASSERT3U(sp->s_rx_prefix_size + off + size, <=,
1572*49ef7e06SGarrett D'Amore 		    (size_t)(srpp->srp_size));
1573*49ef7e06SGarrett D'Amore 
1574*49ef7e06SGarrett D'Amore 		if (sp->s_rx_prefix_size + off + size <
1575*49ef7e06SGarrett D'Amore 		    (size_t)(srpp->srp_size))
1576*49ef7e06SGarrett D'Amore 			mp->b_wptr = mp->b_rptr + off + size;
1577*49ef7e06SGarrett D'Amore 
1578*49ef7e06SGarrett D'Amore 		/*
1579*49ef7e06SGarrett D'Amore 		 * If there is no current flow, or the segment does not match
1580*49ef7e06SGarrett D'Amore 		 * the current flow then we must attempt to look up the
1581*49ef7e06SGarrett D'Amore 		 * correct flow in the table.
1582*49ef7e06SGarrett D'Amore 		 */
1583*49ef7e06SGarrett D'Amore 		if (srfp == NULL)
1584*49ef7e06SGarrett D'Amore 			goto lookup;
1585*49ef7e06SGarrett D'Amore 
1586*49ef7e06SGarrett D'Amore 		if (srfp->srf_saddr != iphp->ip_src.s_addr ||
1587*49ef7e06SGarrett D'Amore 		    srfp->srf_daddr != iphp->ip_dst.s_addr)
1588*49ef7e06SGarrett D'Amore 			goto lookup;
1589*49ef7e06SGarrett D'Amore 
1590*49ef7e06SGarrett D'Amore 		if (srfp->srf_sport != thp->th_sport ||
1591*49ef7e06SGarrett D'Amore 		    srfp->srf_dport != thp->th_dport)
1592*49ef7e06SGarrett D'Amore 			goto lookup;
1593*49ef7e06SGarrett D'Amore 
1594*49ef7e06SGarrett D'Amore 		if (srfp->srf_tci != ether_tci)
1595*49ef7e06SGarrett D'Amore 			goto lookup;
1596*49ef7e06SGarrett D'Amore 
1597*49ef7e06SGarrett D'Amore add:
1598*49ef7e06SGarrett D'Amore 		ASSERT(srfp != NULL);
1599*49ef7e06SGarrett D'Amore 
1600*49ef7e06SGarrett D'Amore 		srpp->srp_etherhp = etherhp;
1601*49ef7e06SGarrett D'Amore 		srpp->srp_iphp = iphp;
1602*49ef7e06SGarrett D'Amore 		srpp->srp_thp = thp;
1603*49ef7e06SGarrett D'Amore 		srpp->srp_off = off;
1604*49ef7e06SGarrett D'Amore 
1605*49ef7e06SGarrett D'Amore 		ASSERT3U(size, <, (1 << 16));
1606*49ef7e06SGarrett D'Amore 		srpp->srp_size = (uint16_t)size;
1607*49ef7e06SGarrett D'Amore 
1608*49ef7e06SGarrett D'Amore 		/* Try to append the packet to the flow */
1609*49ef7e06SGarrett D'Amore 		if (!sfxge_rx_qflow_add(srp, srfp, srpp, now))
1610*49ef7e06SGarrett D'Amore 			goto reject;
1611*49ef7e06SGarrett D'Amore 
1612*49ef7e06SGarrett D'Amore 		mp = next;
1613*49ef7e06SGarrett D'Amore 		continue;
1614*49ef7e06SGarrett D'Amore 
1615*49ef7e06SGarrett D'Amore lookup:
1616*49ef7e06SGarrett D'Amore 		/*
1617*49ef7e06SGarrett D'Amore 		 * If there is a prefix area then read the hash from that,
1618*49ef7e06SGarrett D'Amore 		 * otherwise calculate it.
1619*49ef7e06SGarrett D'Amore 		 */
1620*49ef7e06SGarrett D'Amore 		if (sp->s_rx_prefix_size != 0) {
1621*49ef7e06SGarrett D'Amore 			hash = efx_psuedo_hdr_hash_get(sp->s_enp,
1622*49ef7e06SGarrett D'Amore 			    EFX_RX_HASHALG_TOEPLITZ,
1623*49ef7e06SGarrett D'Amore 			    DB_BASE(mp));
1624*49ef7e06SGarrett D'Amore 		} else {
1625*49ef7e06SGarrett D'Amore 			SFXGE_TCP_HASH(sp,
1626*49ef7e06SGarrett D'Amore 			    &iphp->ip_src.s_addr,
1627*49ef7e06SGarrett D'Amore 			    thp->th_sport,
1628*49ef7e06SGarrett D'Amore 			    &iphp->ip_dst.s_addr,
1629*49ef7e06SGarrett D'Amore 			    thp->th_dport,
1630*49ef7e06SGarrett D'Amore 			    hash);
1631*49ef7e06SGarrett D'Amore 		}
1632*49ef7e06SGarrett D'Amore 
1633*49ef7e06SGarrett D'Amore 		srfp = &(srp->sr_flow[(hash >> 6) % SFXGE_MAX_FLOW]);
1634*49ef7e06SGarrett D'Amore 		tag = hash + 1; /* Make sure it's not zero */
1635*49ef7e06SGarrett D'Amore 
1636*49ef7e06SGarrett D'Amore 		/*
1637*49ef7e06SGarrett D'Amore 		 * If the flow we have found does not match the hash then
1638*49ef7e06SGarrett D'Amore 		 * it may be an unused flow, or it may be stale.
1639*49ef7e06SGarrett D'Amore 		 */
1640*49ef7e06SGarrett D'Amore 		if (tag != srfp->srf_tag) {
1641*49ef7e06SGarrett D'Amore 			if (srfp->srf_count != 0) {
1642*49ef7e06SGarrett D'Amore 				if (now - srfp->srf_lbolt <= srp->sr_rto)
1643*49ef7e06SGarrett D'Amore 					goto reject;
1644*49ef7e06SGarrett D'Amore 			}
1645*49ef7e06SGarrett D'Amore 
1646*49ef7e06SGarrett D'Amore 			if (srfp->srf_mp != NULL)
1647*49ef7e06SGarrett D'Amore 				goto reject;
1648*49ef7e06SGarrett D'Amore 
1649*49ef7e06SGarrett D'Amore 			/* Start a new flow */
1650*49ef7e06SGarrett D'Amore 			ASSERT(srfp->srf_next == NULL);
1651*49ef7e06SGarrett D'Amore 
1652*49ef7e06SGarrett D'Amore 			srfp->srf_tag = tag;
1653*49ef7e06SGarrett D'Amore 
1654*49ef7e06SGarrett D'Amore 			srfp->srf_saddr = iphp->ip_src.s_addr;
1655*49ef7e06SGarrett D'Amore 			srfp->srf_daddr = iphp->ip_dst.s_addr;
1656*49ef7e06SGarrett D'Amore 			srfp->srf_sport = thp->th_sport;
1657*49ef7e06SGarrett D'Amore 			srfp->srf_dport = thp->th_dport;
1658*49ef7e06SGarrett D'Amore 			srfp->srf_tci = ether_tci;
1659*49ef7e06SGarrett D'Amore 
1660*49ef7e06SGarrett D'Amore 			srfp->srf_count = 0;
1661*49ef7e06SGarrett D'Amore 			srfp->srf_seq = ntohl(thp->th_seq);
1662*49ef7e06SGarrett D'Amore 
1663*49ef7e06SGarrett D'Amore 			srfp->srf_lbolt = now;
1664*49ef7e06SGarrett D'Amore 			goto add;
1665*49ef7e06SGarrett D'Amore 		}
1666*49ef7e06SGarrett D'Amore 
1667*49ef7e06SGarrett D'Amore 		/*
1668*49ef7e06SGarrett D'Amore 		 * If the flow we have found does match the hash then it could
1669*49ef7e06SGarrett D'Amore 		 * still be an alias.
1670*49ef7e06SGarrett D'Amore 		 */
1671*49ef7e06SGarrett D'Amore 		if (srfp->srf_saddr != iphp->ip_src.s_addr ||
1672*49ef7e06SGarrett D'Amore 		    srfp->srf_daddr != iphp->ip_dst.s_addr)
1673*49ef7e06SGarrett D'Amore 			goto reject;
1674*49ef7e06SGarrett D'Amore 
1675*49ef7e06SGarrett D'Amore 		if (srfp->srf_sport != thp->th_sport ||
1676*49ef7e06SGarrett D'Amore 		    srfp->srf_dport != thp->th_dport)
1677*49ef7e06SGarrett D'Amore 			goto reject;
1678*49ef7e06SGarrett D'Amore 
1679*49ef7e06SGarrett D'Amore 		if (srfp->srf_tci != ether_tci)
1680*49ef7e06SGarrett D'Amore 			goto reject;
1681*49ef7e06SGarrett D'Amore 
1682*49ef7e06SGarrett D'Amore 		goto add;
1683*49ef7e06SGarrett D'Amore 
1684*49ef7e06SGarrett D'Amore reject:
1685*49ef7e06SGarrett D'Amore 		*(srp->sr_mpp) = mp;
1686*49ef7e06SGarrett D'Amore 		srp->sr_mpp = &(mp->b_next);
1687*49ef7e06SGarrett D'Amore 
1688*49ef7e06SGarrett D'Amore 		mp = next;
1689*49ef7e06SGarrett D'Amore 	}
1690*49ef7e06SGarrett D'Amore }
1691*49ef7e06SGarrett D'Amore 
1692*49ef7e06SGarrett D'Amore void
sfxge_rx_qcomplete(sfxge_rxq_t * srp,boolean_t eop)1693*49ef7e06SGarrett D'Amore sfxge_rx_qcomplete(sfxge_rxq_t *srp, boolean_t eop)
1694*49ef7e06SGarrett D'Amore {
1695*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1696*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1697*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1698*49ef7e06SGarrett D'Amore 	unsigned int completed;
1699*49ef7e06SGarrett D'Amore 	sfxge_rx_fpp_t *srfppp = &(srp->sr_fpp);
1700*49ef7e06SGarrett D'Amore 	unsigned int level;
1701*49ef7e06SGarrett D'Amore 
1702*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
1703*49ef7e06SGarrett D'Amore 
1704*49ef7e06SGarrett D'Amore 	ASSERT(srp->sr_mp == NULL);
1705*49ef7e06SGarrett D'Amore 	ASSERT(srp->sr_mpp == &(srp->sr_mp));
1706*49ef7e06SGarrett D'Amore 
1707*49ef7e06SGarrett D'Amore 	completed = srp->sr_completed;
1708*49ef7e06SGarrett D'Amore 	while (completed != srp->sr_pending) {
1709*49ef7e06SGarrett D'Amore 		unsigned int id;
1710*49ef7e06SGarrett D'Amore 		sfxge_rx_packet_t *srpp;
1711*49ef7e06SGarrett D'Amore 		mblk_t *mp;
1712*49ef7e06SGarrett D'Amore 		size_t size;
1713*49ef7e06SGarrett D'Amore 		uint16_t flags;
1714*49ef7e06SGarrett D'Amore 		int rc;
1715*49ef7e06SGarrett D'Amore 
1716*49ef7e06SGarrett D'Amore 		id = completed++ & (sp->s_rxq_size - 1);
1717*49ef7e06SGarrett D'Amore 
1718*49ef7e06SGarrett D'Amore 		if (srp->sr_pending - completed >= 4) {
1719*49ef7e06SGarrett D'Amore 			unsigned int prefetch;
1720*49ef7e06SGarrett D'Amore 
1721*49ef7e06SGarrett D'Amore 			prefetch = (id + 4) & (sp->s_rxq_size - 1);
1722*49ef7e06SGarrett D'Amore 
1723*49ef7e06SGarrett D'Amore 			srpp = srp->sr_srpp[prefetch];
1724*49ef7e06SGarrett D'Amore 			ASSERT(srpp != NULL);
1725*49ef7e06SGarrett D'Amore 
1726*49ef7e06SGarrett D'Amore 			mp = srpp->srp_mp;
1727*49ef7e06SGarrett D'Amore 			prefetch_read_many(mp->b_datap);
1728*49ef7e06SGarrett D'Amore 		} else if (completed == srp->sr_pending) {
1729*49ef7e06SGarrett D'Amore 			prefetch_read_many(srp->sr_mp);
1730*49ef7e06SGarrett D'Amore 		}
1731*49ef7e06SGarrett D'Amore 
1732*49ef7e06SGarrett D'Amore 		srpp = srp->sr_srpp[id];
1733*49ef7e06SGarrett D'Amore 		ASSERT(srpp != NULL);
1734*49ef7e06SGarrett D'Amore 
1735*49ef7e06SGarrett D'Amore 		srp->sr_srpp[id] = NULL;
1736*49ef7e06SGarrett D'Amore 
1737*49ef7e06SGarrett D'Amore 		mp = srpp->srp_mp;
1738*49ef7e06SGarrett D'Amore 		ASSERT(mp->b_cont == NULL);
1739*49ef7e06SGarrett D'Amore 
1740*49ef7e06SGarrett D'Amore 		/* when called from sfxge_rx_qstop() */
1741*49ef7e06SGarrett D'Amore 		if (srp->sr_state != SFXGE_RXQ_STARTED)
1742*49ef7e06SGarrett D'Amore 			goto discard;
1743*49ef7e06SGarrett D'Amore 
1744*49ef7e06SGarrett D'Amore 		if (srpp->srp_flags & (EFX_ADDR_MISMATCH | EFX_DISCARD))
1745*49ef7e06SGarrett D'Amore 			goto discard;
1746*49ef7e06SGarrett D'Amore 
1747*49ef7e06SGarrett D'Amore 		/* Make the data visible to the kernel */
1748*49ef7e06SGarrett D'Amore 		rc = ddi_dma_sync(srpp->srp_dma_handle, 0,
1749*49ef7e06SGarrett D'Amore 		    sp->s_rx_buffer_size, DDI_DMA_SYNC_FORKERNEL);
1750*49ef7e06SGarrett D'Amore 		ASSERT3P(rc, ==, DDI_SUCCESS);
1751*49ef7e06SGarrett D'Amore 
1752*49ef7e06SGarrett D'Amore 		/* Read the length from the psuedo header if required */
1753*49ef7e06SGarrett D'Amore 		if (srpp->srp_flags & EFX_PKT_PREFIX_LEN) {
1754*49ef7e06SGarrett D'Amore 			rc = efx_psuedo_hdr_pkt_length_get(sp->s_enp,
1755*49ef7e06SGarrett D'Amore 			    mp->b_rptr,
1756*49ef7e06SGarrett D'Amore 			    &srpp->srp_size);
1757*49ef7e06SGarrett D'Amore 			ASSERT3P(rc, ==, 0);
1758*49ef7e06SGarrett D'Amore 			srpp->srp_size += sp->s_rx_prefix_size;
1759*49ef7e06SGarrett D'Amore 		}
1760*49ef7e06SGarrett D'Amore 
1761*49ef7e06SGarrett D'Amore 		/* Set up the packet length */
1762*49ef7e06SGarrett D'Amore 		ASSERT3P(mp->b_rptr, ==, DB_BASE(mp));
1763*49ef7e06SGarrett D'Amore 		mp->b_rptr += sp->s_rx_prefix_size;
1764*49ef7e06SGarrett D'Amore 
1765*49ef7e06SGarrett D'Amore 		prefetch_read_many(mp->b_rptr);
1766*49ef7e06SGarrett D'Amore 
1767*49ef7e06SGarrett D'Amore 		ASSERT3P(mp->b_wptr, ==, DB_BASE(mp));
1768*49ef7e06SGarrett D'Amore 		mp->b_wptr += (size_t)(srpp->srp_size);
1769*49ef7e06SGarrett D'Amore 		ASSERT3P(mp->b_wptr, <=, DB_LIM(mp));
1770*49ef7e06SGarrett D'Amore 
1771*49ef7e06SGarrett D'Amore 		/* Calculate the maximum packet size */
1772*49ef7e06SGarrett D'Amore 		size = sp->s_mtu;
1773*49ef7e06SGarrett D'Amore 		size += (srpp->srp_flags & EFX_PKT_VLAN_TAGGED) ?
1774*49ef7e06SGarrett D'Amore 		    sizeof (struct ether_vlan_header) :
1775*49ef7e06SGarrett D'Amore 		    sizeof (struct ether_header);
1776*49ef7e06SGarrett D'Amore 
1777*49ef7e06SGarrett D'Amore 		if (MBLKL(mp) > size)
1778*49ef7e06SGarrett D'Amore 			goto discard;
1779*49ef7e06SGarrett D'Amore 
1780*49ef7e06SGarrett D'Amore 		/* Check for loopback packets */
1781*49ef7e06SGarrett D'Amore 		if (!(srpp->srp_flags & EFX_PKT_IPV4) &&
1782*49ef7e06SGarrett D'Amore 		    !(srpp->srp_flags & EFX_PKT_IPV6)) {
1783*49ef7e06SGarrett D'Amore 			struct ether_header *etherhp;
1784*49ef7e06SGarrett D'Amore 
1785*49ef7e06SGarrett D'Amore 			/*LINTED*/
1786*49ef7e06SGarrett D'Amore 			etherhp = (struct ether_header *)(mp->b_rptr);
1787*49ef7e06SGarrett D'Amore 
1788*49ef7e06SGarrett D'Amore 			if (etherhp->ether_type ==
1789*49ef7e06SGarrett D'Amore 			    htons(SFXGE_ETHERTYPE_LOOPBACK)) {
1790*49ef7e06SGarrett D'Amore 				DTRACE_PROBE(loopback);
1791*49ef7e06SGarrett D'Amore 
1792*49ef7e06SGarrett D'Amore 				srp->sr_loopback++;
1793*49ef7e06SGarrett D'Amore 				goto discard;
1794*49ef7e06SGarrett D'Amore 			}
1795*49ef7e06SGarrett D'Amore 		}
1796*49ef7e06SGarrett D'Amore 
1797*49ef7e06SGarrett D'Amore 		/* Set up the checksum information */
1798*49ef7e06SGarrett D'Amore 		flags = 0;
1799*49ef7e06SGarrett D'Amore 
1800*49ef7e06SGarrett D'Amore 		if (srpp->srp_flags & EFX_CKSUM_IPV4) {
1801*49ef7e06SGarrett D'Amore 			ASSERT(srpp->srp_flags & EFX_PKT_IPV4);
1802*49ef7e06SGarrett D'Amore 			flags |= HCK_IPV4_HDRCKSUM;
1803*49ef7e06SGarrett D'Amore 		}
1804*49ef7e06SGarrett D'Amore 
1805*49ef7e06SGarrett D'Amore 		if (srpp->srp_flags & EFX_CKSUM_TCPUDP) {
1806*49ef7e06SGarrett D'Amore 			ASSERT(srpp->srp_flags & EFX_PKT_TCP ||
1807*49ef7e06SGarrett D'Amore 			    srpp->srp_flags & EFX_PKT_UDP);
1808*49ef7e06SGarrett D'Amore 			flags |= HCK_FULLCKSUM | HCK_FULLCKSUM_OK;
1809*49ef7e06SGarrett D'Amore 		}
1810*49ef7e06SGarrett D'Amore 
1811*49ef7e06SGarrett D'Amore 		DB_CKSUMSTART(mp) = 0;
1812*49ef7e06SGarrett D'Amore 		DB_CKSUMSTUFF(mp) = 0;
1813*49ef7e06SGarrett D'Amore 		DB_CKSUMEND(mp) = 0;
1814*49ef7e06SGarrett D'Amore 		DB_CKSUMFLAGS(mp) = flags;
1815*49ef7e06SGarrett D'Amore 		DB_CKSUM16(mp) = 0;
1816*49ef7e06SGarrett D'Amore 
1817*49ef7e06SGarrett D'Amore 		/* Add the packet to the tail of the chain */
1818*49ef7e06SGarrett D'Amore 		srfppp->srfpp_loaned++;
1819*49ef7e06SGarrett D'Amore 
1820*49ef7e06SGarrett D'Amore 		ASSERT(mp->b_next == NULL);
1821*49ef7e06SGarrett D'Amore 		*(srp->sr_mpp) = mp;
1822*49ef7e06SGarrett D'Amore 		srp->sr_mpp = &(mp->b_next);
1823*49ef7e06SGarrett D'Amore 
1824*49ef7e06SGarrett D'Amore 		continue;
1825*49ef7e06SGarrett D'Amore 
1826*49ef7e06SGarrett D'Amore discard:
1827*49ef7e06SGarrett D'Amore 		/* Return the packet to the pool */
1828*49ef7e06SGarrett D'Amore 		srfppp->srfpp_loaned++;
1829*49ef7e06SGarrett D'Amore 		freeb(mp); /* Equivalent to freemsg() as b_cont==0 */
1830*49ef7e06SGarrett D'Amore 	}
1831*49ef7e06SGarrett D'Amore 	srp->sr_completed = completed;
1832*49ef7e06SGarrett D'Amore 
1833*49ef7e06SGarrett D'Amore 	/* Attempt to coalesce any TCP packets */
1834*49ef7e06SGarrett D'Amore 	if (sp->s_rx_coalesce_mode != SFXGE_RX_COALESCE_OFF)
1835*49ef7e06SGarrett D'Amore 		sfxge_rx_qpacket_coalesce(srp);
1836*49ef7e06SGarrett D'Amore 
1837*49ef7e06SGarrett D'Amore 	/*
1838*49ef7e06SGarrett D'Amore 	 * If there are any pending flows and this is the end of the
1839*49ef7e06SGarrett D'Amore 	 * poll then they must be completed.
1840*49ef7e06SGarrett D'Amore 	 */
1841*49ef7e06SGarrett D'Amore 	if (srp->sr_srfp != NULL && eop) {
1842*49ef7e06SGarrett D'Amore 		sfxge_rx_flow_t *srfp;
1843*49ef7e06SGarrett D'Amore 
1844*49ef7e06SGarrett D'Amore 		srfp = srp->sr_srfp;
1845*49ef7e06SGarrett D'Amore 
1846*49ef7e06SGarrett D'Amore 		srp->sr_srfp = NULL;
1847*49ef7e06SGarrett D'Amore 		srp->sr_srfpp = &(srp->sr_srfp);
1848*49ef7e06SGarrett D'Amore 
1849*49ef7e06SGarrett D'Amore 		do {
1850*49ef7e06SGarrett D'Amore 			sfxge_rx_flow_t *next;
1851*49ef7e06SGarrett D'Amore 
1852*49ef7e06SGarrett D'Amore 			next = srfp->srf_next;
1853*49ef7e06SGarrett D'Amore 			srfp->srf_next = NULL;
1854*49ef7e06SGarrett D'Amore 
1855*49ef7e06SGarrett D'Amore 			sfxge_rx_qflow_complete(srp, srfp);
1856*49ef7e06SGarrett D'Amore 
1857*49ef7e06SGarrett D'Amore 			srfp = next;
1858*49ef7e06SGarrett D'Amore 		} while (srfp != NULL);
1859*49ef7e06SGarrett D'Amore 	}
1860*49ef7e06SGarrett D'Amore 
1861*49ef7e06SGarrett D'Amore 	level = srp->sr_pushed - srp->sr_completed;
1862*49ef7e06SGarrett D'Amore 
1863*49ef7e06SGarrett D'Amore 	/* If there are any packets then pass them up the stack */
1864*49ef7e06SGarrett D'Amore 	if (srp->sr_mp != NULL) {
1865*49ef7e06SGarrett D'Amore 		mblk_t *mp;
1866*49ef7e06SGarrett D'Amore 
1867*49ef7e06SGarrett D'Amore 		mp = srp->sr_mp;
1868*49ef7e06SGarrett D'Amore 
1869*49ef7e06SGarrett D'Amore 		srp->sr_mp = NULL;
1870*49ef7e06SGarrett D'Amore 		srp->sr_mpp = &(srp->sr_mp);
1871*49ef7e06SGarrett D'Amore 
1872*49ef7e06SGarrett D'Amore 		if (level == 0) {
1873*49ef7e06SGarrett D'Amore 			/* Try to refill ASAP */
1874*49ef7e06SGarrett D'Amore 			sfxge_rx_qrefill(srp, EFX_RXQ_LIMIT(sp->s_rxq_size));
1875*49ef7e06SGarrett D'Amore 			level = srp->sr_pushed - srp->sr_completed;
1876*49ef7e06SGarrett D'Amore 		}
1877*49ef7e06SGarrett D'Amore 
1878*49ef7e06SGarrett D'Amore 		/*
1879*49ef7e06SGarrett D'Amore 		 * If the RXQ is still empty, discard and recycle the
1880*49ef7e06SGarrett D'Amore 		 * current entry to ensure that the ring always
1881*49ef7e06SGarrett D'Amore 		 * contains at least one descriptor. This ensures that
1882*49ef7e06SGarrett D'Amore 		 * the next hardware RX will trigger an event
1883*49ef7e06SGarrett D'Amore 		 * (possibly delayed by interrupt moderation) and
1884*49ef7e06SGarrett D'Amore 		 * trigger another refill/fill attempt.
1885*49ef7e06SGarrett D'Amore 		 *
1886*49ef7e06SGarrett D'Amore 		 * Note this drops a complete LRO fragment from the
1887*49ef7e06SGarrett D'Amore 		 * start of the batch.
1888*49ef7e06SGarrett D'Amore 		 *
1889*49ef7e06SGarrett D'Amore 		 * Note also that copymsgchain() does not help with
1890*49ef7e06SGarrett D'Amore 		 * resource starvation here, unless we are short of DMA
1891*49ef7e06SGarrett D'Amore 		 * mappings.
1892*49ef7e06SGarrett D'Amore 		 */
1893*49ef7e06SGarrett D'Amore 		if (level == 0) {
1894*49ef7e06SGarrett D'Amore 			mblk_t *nmp;
1895*49ef7e06SGarrett D'Amore 
1896*49ef7e06SGarrett D'Amore 			srp->sr_kstat.srk_rxq_empty_discard++;
1897*49ef7e06SGarrett D'Amore 			DTRACE_PROBE1(rxq_empty_discard, int, index);
1898*49ef7e06SGarrett D'Amore 			nmp = mp->b_next;
1899*49ef7e06SGarrett D'Amore 			if (nmp)
1900*49ef7e06SGarrett D'Amore 				sfxge_gld_rx_post(sp, index, nmp);
1901*49ef7e06SGarrett D'Amore 			/* as level==0 will swizzle,rxpost below */
1902*49ef7e06SGarrett D'Amore 			freemsg(mp);
1903*49ef7e06SGarrett D'Amore 		} else {
1904*49ef7e06SGarrett D'Amore 			sfxge_gld_rx_post(sp, index, mp);
1905*49ef7e06SGarrett D'Amore 		}
1906*49ef7e06SGarrett D'Amore 	}
1907*49ef7e06SGarrett D'Amore 
1908*49ef7e06SGarrett D'Amore 	/* Top up the queue if necessary */
1909*49ef7e06SGarrett D'Amore 	if (level < srp->sr_hiwat) {
1910*49ef7e06SGarrett D'Amore 		sfxge_rx_qrefill(srp, EFX_RXQ_LIMIT(sp->s_rxq_size));
1911*49ef7e06SGarrett D'Amore 
1912*49ef7e06SGarrett D'Amore 		level = srp->sr_added - srp->sr_completed;
1913*49ef7e06SGarrett D'Amore 		if (level < srp->sr_lowat)
1914*49ef7e06SGarrett D'Amore 			sfxge_rx_qfill(srp, EFX_RXQ_LIMIT(sp->s_rxq_size));
1915*49ef7e06SGarrett D'Amore 	}
1916*49ef7e06SGarrett D'Amore }
1917*49ef7e06SGarrett D'Amore 
1918*49ef7e06SGarrett D'Amore void
sfxge_rx_qflush_done(sfxge_rxq_t * srp)1919*49ef7e06SGarrett D'Amore sfxge_rx_qflush_done(sfxge_rxq_t *srp)
1920*49ef7e06SGarrett D'Amore {
1921*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1922*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1923*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1924*49ef7e06SGarrett D'Amore 	boolean_t flush_pending;
1925*49ef7e06SGarrett D'Amore 
1926*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
1927*49ef7e06SGarrett D'Amore 
1928*49ef7e06SGarrett D'Amore 	/*
1929*49ef7e06SGarrett D'Amore 	 * Flush successful: wakeup sfxge_rx_qstop() if flush is pending.
1930*49ef7e06SGarrett D'Amore 	 *
1931*49ef7e06SGarrett D'Amore 	 * A delayed flush event received after RxQ stop has timed out
1932*49ef7e06SGarrett D'Amore 	 * will be ignored, as then the flush state will not be PENDING
1933*49ef7e06SGarrett D'Amore 	 * (see SFCbug22989).
1934*49ef7e06SGarrett D'Amore 	 */
1935*49ef7e06SGarrett D'Amore 	flush_pending = (srp->sr_flush == SFXGE_FLUSH_PENDING);
1936*49ef7e06SGarrett D'Amore 	srp->sr_flush = SFXGE_FLUSH_DONE;
1937*49ef7e06SGarrett D'Amore 	if (flush_pending)
1938*49ef7e06SGarrett D'Amore 		cv_broadcast(&(srp->sr_flush_kv));
1939*49ef7e06SGarrett D'Amore }
1940*49ef7e06SGarrett D'Amore 
1941*49ef7e06SGarrett D'Amore void
sfxge_rx_qflush_failed(sfxge_rxq_t * srp)1942*49ef7e06SGarrett D'Amore sfxge_rx_qflush_failed(sfxge_rxq_t *srp)
1943*49ef7e06SGarrett D'Amore {
1944*49ef7e06SGarrett D'Amore 	sfxge_t *sp = srp->sr_sp;
1945*49ef7e06SGarrett D'Amore 	unsigned int index = srp->sr_index;
1946*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1947*49ef7e06SGarrett D'Amore 	boolean_t flush_pending;
1948*49ef7e06SGarrett D'Amore 
1949*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sep->se_lock)));
1950*49ef7e06SGarrett D'Amore 
1951*49ef7e06SGarrett D'Amore 	/*
1952*49ef7e06SGarrett D'Amore 	 * Flush failed: wakeup sfxge_rx_qstop() if flush is pending.
1953*49ef7e06SGarrett D'Amore 	 *
1954*49ef7e06SGarrett D'Amore 	 * A delayed flush event received after RxQ stop has timed out
1955*49ef7e06SGarrett D'Amore 	 * will be ignored, as then the flush state will not be PENDING
1956*49ef7e06SGarrett D'Amore 	 * (see SFCbug22989).
1957*49ef7e06SGarrett D'Amore 	 */
1958*49ef7e06SGarrett D'Amore 	flush_pending = (srp->sr_flush == SFXGE_FLUSH_PENDING);
1959*49ef7e06SGarrett D'Amore 	srp->sr_flush = SFXGE_FLUSH_FAILED;
1960*49ef7e06SGarrett D'Amore 	if (flush_pending)
1961*49ef7e06SGarrett D'Amore 		cv_broadcast(&(srp->sr_flush_kv));
1962*49ef7e06SGarrett D'Amore }
1963*49ef7e06SGarrett D'Amore 
1964*49ef7e06SGarrett D'Amore static void
sfxge_rx_qstop(sfxge_t * sp,unsigned int index)1965*49ef7e06SGarrett D'Amore sfxge_rx_qstop(sfxge_t *sp, unsigned int index)
1966*49ef7e06SGarrett D'Amore {
1967*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
1968*49ef7e06SGarrett D'Amore 	sfxge_evq_t *sep = sp->s_sep[index];
1969*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp;
1970*49ef7e06SGarrett D'Amore 	clock_t timeout;
1971*49ef7e06SGarrett D'Amore 	unsigned int flush_tries = SFXGE_RX_QFLUSH_TRIES;
1972*49ef7e06SGarrett D'Amore 	int rc;
1973*49ef7e06SGarrett D'Amore 
1974*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sp->s_state_lock)));
1975*49ef7e06SGarrett D'Amore 
1976*49ef7e06SGarrett D'Amore 	mutex_enter(&(sep->se_lock));
1977*49ef7e06SGarrett D'Amore 
1978*49ef7e06SGarrett D'Amore 	srp = sp->s_srp[index];
1979*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_STARTED);
1980*49ef7e06SGarrett D'Amore 
1981*49ef7e06SGarrett D'Amore 	sfxge_rx_qpoll_stop(srp);
1982*49ef7e06SGarrett D'Amore 
1983*49ef7e06SGarrett D'Amore 	/* Further packets are discarded by sfxge_rx_qcomplete() */
1984*49ef7e06SGarrett D'Amore 	srp->sr_state = SFXGE_RXQ_INITIALIZED;
1985*49ef7e06SGarrett D'Amore 
1986*49ef7e06SGarrett D'Amore 	if (sp->s_hw_err != SFXGE_HW_OK) {
1987*49ef7e06SGarrett D'Amore 		/*
1988*49ef7e06SGarrett D'Amore 		 * Flag indicates possible hardware failure.
1989*49ef7e06SGarrett D'Amore 		 * Attempt flush but do not wait for it to complete.
1990*49ef7e06SGarrett D'Amore 		 */
1991*49ef7e06SGarrett D'Amore 		srp->sr_flush = SFXGE_FLUSH_DONE;
1992*49ef7e06SGarrett D'Amore 		(void) efx_rx_qflush(srp->sr_erp);
1993*49ef7e06SGarrett D'Amore 	}
1994*49ef7e06SGarrett D'Amore 
1995*49ef7e06SGarrett D'Amore 	/* Wait upto 2sec for queue flushing to complete */
1996*49ef7e06SGarrett D'Amore 	timeout = ddi_get_lbolt() + drv_usectohz(SFXGE_RX_QFLUSH_USEC);
1997*49ef7e06SGarrett D'Amore 
1998*49ef7e06SGarrett D'Amore 	while (srp->sr_flush != SFXGE_FLUSH_DONE && flush_tries-- > 0) {
1999*49ef7e06SGarrett D'Amore 		if ((rc = efx_rx_qflush(srp->sr_erp)) != 0) {
2000*49ef7e06SGarrett D'Amore 			if (rc == EALREADY)
2001*49ef7e06SGarrett D'Amore 				srp->sr_flush = SFXGE_FLUSH_DONE;
2002*49ef7e06SGarrett D'Amore 			else
2003*49ef7e06SGarrett D'Amore 				srp->sr_flush = SFXGE_FLUSH_FAILED;
2004*49ef7e06SGarrett D'Amore 			break;
2005*49ef7e06SGarrett D'Amore 		}
2006*49ef7e06SGarrett D'Amore 		srp->sr_flush = SFXGE_FLUSH_PENDING;
2007*49ef7e06SGarrett D'Amore 		if (cv_timedwait(&(srp->sr_flush_kv), &(sep->se_lock),
2008*49ef7e06SGarrett D'Amore 		    timeout) < 0) {
2009*49ef7e06SGarrett D'Amore 			/* Timeout waiting for successful or failed flush */
2010*49ef7e06SGarrett D'Amore 			dev_err(dip, CE_NOTE,
2011*49ef7e06SGarrett D'Amore 			    SFXGE_CMN_ERR "rxq[%d] flush timeout", index);
2012*49ef7e06SGarrett D'Amore 			break;
2013*49ef7e06SGarrett D'Amore 		}
2014*49ef7e06SGarrett D'Amore 	}
2015*49ef7e06SGarrett D'Amore 
2016*49ef7e06SGarrett D'Amore 	if (srp->sr_flush == SFXGE_FLUSH_FAILED)
2017*49ef7e06SGarrett D'Amore 		dev_err(dip, CE_NOTE,
2018*49ef7e06SGarrett D'Amore 		    SFXGE_CMN_ERR "rxq[%d] flush failed", index);
2019*49ef7e06SGarrett D'Amore 
2020*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(flush, sfxge_flush_state_t, srp->sr_flush);
2021*49ef7e06SGarrett D'Amore 	srp->sr_flush = SFXGE_FLUSH_DONE;
2022*49ef7e06SGarrett D'Amore 
2023*49ef7e06SGarrett D'Amore 	/* Destroy the receive queue */
2024*49ef7e06SGarrett D'Amore 	efx_rx_qdestroy(srp->sr_erp);
2025*49ef7e06SGarrett D'Amore 	srp->sr_erp = NULL;
2026*49ef7e06SGarrett D'Amore 
2027*49ef7e06SGarrett D'Amore 	/* Clear entries from the buffer table */
2028*49ef7e06SGarrett D'Amore 	sfxge_sram_buf_tbl_clear(sp, srp->sr_id,
2029*49ef7e06SGarrett D'Amore 	    EFX_RXQ_NBUFS(sp->s_rxq_size));
2030*49ef7e06SGarrett D'Amore 
2031*49ef7e06SGarrett D'Amore 	/*
2032*49ef7e06SGarrett D'Amore 	 * Free any unused RX packets which had descriptors on the RXQ
2033*49ef7e06SGarrett D'Amore 	 * Packets will be discard as state != STARTED
2034*49ef7e06SGarrett D'Amore 	 */
2035*49ef7e06SGarrett D'Amore 	srp->sr_pending = srp->sr_added;
2036*49ef7e06SGarrett D'Amore 	sfxge_rx_qcomplete(srp, B_TRUE);
2037*49ef7e06SGarrett D'Amore 
2038*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_completed, ==, srp->sr_pending);
2039*49ef7e06SGarrett D'Amore 
2040*49ef7e06SGarrett D'Amore 	srp->sr_added = 0;
2041*49ef7e06SGarrett D'Amore 	srp->sr_pushed = 0;
2042*49ef7e06SGarrett D'Amore 	srp->sr_pending = 0;
2043*49ef7e06SGarrett D'Amore 	srp->sr_completed = 0;
2044*49ef7e06SGarrett D'Amore 	srp->sr_loopback = 0;
2045*49ef7e06SGarrett D'Amore 
2046*49ef7e06SGarrett D'Amore 	srp->sr_lowat = 0;
2047*49ef7e06SGarrett D'Amore 	srp->sr_hiwat = 0;
2048*49ef7e06SGarrett D'Amore 
2049*49ef7e06SGarrett D'Amore 	mutex_exit(&(sep->se_lock));
2050*49ef7e06SGarrett D'Amore }
2051*49ef7e06SGarrett D'Amore 
2052*49ef7e06SGarrett D'Amore static void
sfxge_rx_kstat_fini(sfxge_rxq_t * srp)2053*49ef7e06SGarrett D'Amore sfxge_rx_kstat_fini(sfxge_rxq_t *srp)
2054*49ef7e06SGarrett D'Amore {
2055*49ef7e06SGarrett D'Amore 	kstat_delete(srp->sr_ksp);
2056*49ef7e06SGarrett D'Amore 	srp->sr_ksp = NULL;
2057*49ef7e06SGarrett D'Amore }
2058*49ef7e06SGarrett D'Amore 
2059*49ef7e06SGarrett D'Amore static void
sfxge_rx_qfini(sfxge_t * sp,unsigned int index)2060*49ef7e06SGarrett D'Amore sfxge_rx_qfini(sfxge_t *sp, unsigned int index)
2061*49ef7e06SGarrett D'Amore {
2062*49ef7e06SGarrett D'Amore 	sfxge_rxq_t *srp = sp->s_srp[index];
2063*49ef7e06SGarrett D'Amore 
2064*49ef7e06SGarrett D'Amore 	ASSERT3U(srp->sr_state, ==, SFXGE_RXQ_INITIALIZED);
2065*49ef7e06SGarrett D'Amore 
2066*49ef7e06SGarrett D'Amore 	sp->s_srp[index] = NULL;
2067*49ef7e06SGarrett D'Amore 	srp->sr_state = SFXGE_RXQ_UNINITIALIZED;
2068*49ef7e06SGarrett D'Amore 
2069*49ef7e06SGarrett D'Amore 	sfxge_rx_kstat_fini(srp);
2070*49ef7e06SGarrett D'Amore 
2071*49ef7e06SGarrett D'Amore 	/* Empty the pool */
2072*49ef7e06SGarrett D'Amore 	sfxge_rx_qfpp_empty(srp);
2073*49ef7e06SGarrett D'Amore 
2074*49ef7e06SGarrett D'Amore 	srp->sr_index = 0;
2075*49ef7e06SGarrett D'Amore 
2076*49ef7e06SGarrett D'Amore 	kmem_cache_free(sp->s_rqc, srp);
2077*49ef7e06SGarrett D'Amore }
2078*49ef7e06SGarrett D'Amore 
2079*49ef7e06SGarrett D'Amore static int
sfxge_rx_scale_kstat_update(kstat_t * ksp,int rw)2080*49ef7e06SGarrett D'Amore sfxge_rx_scale_kstat_update(kstat_t *ksp, int rw)
2081*49ef7e06SGarrett D'Amore {
2082*49ef7e06SGarrett D'Amore 	sfxge_t *sp = ksp->ks_private;
2083*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2084*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2085*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
2086*49ef7e06SGarrett D'Amore 	unsigned int index;
2087*49ef7e06SGarrett D'Amore 	unsigned int entry;
2088*49ef7e06SGarrett D'Amore 	unsigned int *freq;
2089*49ef7e06SGarrett D'Amore 	int rc;
2090*49ef7e06SGarrett D'Amore 
2091*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(srsp->srs_lock)));
2092*49ef7e06SGarrett D'Amore 
2093*49ef7e06SGarrett D'Amore 	if (rw != KSTAT_READ) {
2094*49ef7e06SGarrett D'Amore 		rc = EACCES;
2095*49ef7e06SGarrett D'Amore 		goto fail1;
2096*49ef7e06SGarrett D'Amore 	}
2097*49ef7e06SGarrett D'Amore 
2098*49ef7e06SGarrett D'Amore 	if ((freq = kmem_zalloc(sizeof (unsigned int) * sip->si_nalloc,
2099*49ef7e06SGarrett D'Amore 	    KM_NOSLEEP)) == NULL) {
2100*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
2101*49ef7e06SGarrett D'Amore 		goto fail2;
2102*49ef7e06SGarrett D'Amore 	}
2103*49ef7e06SGarrett D'Amore 
2104*49ef7e06SGarrett D'Amore 	for (entry = 0; entry < SFXGE_RX_SCALE_MAX; entry++) {
2105*49ef7e06SGarrett D'Amore 		index = srsp->srs_tbl[entry];
2106*49ef7e06SGarrett D'Amore 
2107*49ef7e06SGarrett D'Amore 		freq[index]++;
2108*49ef7e06SGarrett D'Amore 	}
2109*49ef7e06SGarrett D'Amore 
2110*49ef7e06SGarrett D'Amore 	knp = ksp->ks_data;
2111*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
2112*49ef7e06SGarrett D'Amore 		knp->value.ui64 = freq[index];
2113*49ef7e06SGarrett D'Amore 		knp++;
2114*49ef7e06SGarrett D'Amore 	}
2115*49ef7e06SGarrett D'Amore 
2116*49ef7e06SGarrett D'Amore 	knp->value.ui64 = srsp->srs_count;
2117*49ef7e06SGarrett D'Amore 
2118*49ef7e06SGarrett D'Amore 	kmem_free(freq, sizeof (unsigned int) * sip->si_nalloc);
2119*49ef7e06SGarrett D'Amore 
2120*49ef7e06SGarrett D'Amore 	return (0);
2121*49ef7e06SGarrett D'Amore 
2122*49ef7e06SGarrett D'Amore fail2:
2123*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2124*49ef7e06SGarrett D'Amore fail1:
2125*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2126*49ef7e06SGarrett D'Amore 	return (rc);
2127*49ef7e06SGarrett D'Amore }
2128*49ef7e06SGarrett D'Amore 
2129*49ef7e06SGarrett D'Amore static int
sfxge_rx_scale_kstat_init(sfxge_t * sp)2130*49ef7e06SGarrett D'Amore sfxge_rx_scale_kstat_init(sfxge_t *sp)
2131*49ef7e06SGarrett D'Amore {
2132*49ef7e06SGarrett D'Amore 	dev_info_t *dip = sp->s_dip;
2133*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2134*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2135*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
2136*49ef7e06SGarrett D'Amore 	kstat_t *ksp;
2137*49ef7e06SGarrett D'Amore 	kstat_named_t *knp;
2138*49ef7e06SGarrett D'Amore 	unsigned int index;
2139*49ef7e06SGarrett D'Amore 	int rc;
2140*49ef7e06SGarrett D'Amore 
2141*49ef7e06SGarrett D'Amore 	/* Create the set */
2142*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s_rss", ddi_driver_name(dip));
2143*49ef7e06SGarrett D'Amore 
2144*49ef7e06SGarrett D'Amore 	if ((ksp = kstat_create((char *)ddi_driver_name(dip),
2145*49ef7e06SGarrett D'Amore 	    ddi_get_instance(dip), name, "rss", KSTAT_TYPE_NAMED,
2146*49ef7e06SGarrett D'Amore 	    sip->si_nalloc + 1, 0)) == NULL) {
2147*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
2148*49ef7e06SGarrett D'Amore 		goto fail1;
2149*49ef7e06SGarrett D'Amore 	}
2150*49ef7e06SGarrett D'Amore 
2151*49ef7e06SGarrett D'Amore 	srsp->srs_ksp = ksp;
2152*49ef7e06SGarrett D'Amore 
2153*49ef7e06SGarrett D'Amore 	ksp->ks_update = sfxge_rx_scale_kstat_update;
2154*49ef7e06SGarrett D'Amore 	ksp->ks_private = sp;
2155*49ef7e06SGarrett D'Amore 	ksp->ks_lock = &(srsp->srs_lock);
2156*49ef7e06SGarrett D'Amore 
2157*49ef7e06SGarrett D'Amore 	/* Initialise the named stats */
2158*49ef7e06SGarrett D'Amore 	knp = ksp->ks_data;
2159*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
2160*49ef7e06SGarrett D'Amore 		char name[MAXNAMELEN];
2161*49ef7e06SGarrett D'Amore 
2162*49ef7e06SGarrett D'Amore 		(void) snprintf(name, MAXNAMELEN - 1, "evq%04d_count", index);
2163*49ef7e06SGarrett D'Amore 		kstat_named_init(knp, name, KSTAT_DATA_UINT64);
2164*49ef7e06SGarrett D'Amore 		knp++;
2165*49ef7e06SGarrett D'Amore 	}
2166*49ef7e06SGarrett D'Amore 
2167*49ef7e06SGarrett D'Amore 	kstat_named_init(knp, "scale", KSTAT_DATA_UINT64);
2168*49ef7e06SGarrett D'Amore 
2169*49ef7e06SGarrett D'Amore 	kstat_install(ksp);
2170*49ef7e06SGarrett D'Amore 	return (0);
2171*49ef7e06SGarrett D'Amore 
2172*49ef7e06SGarrett D'Amore fail1:
2173*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2174*49ef7e06SGarrett D'Amore 
2175*49ef7e06SGarrett D'Amore 	return (rc);
2176*49ef7e06SGarrett D'Amore }
2177*49ef7e06SGarrett D'Amore 
2178*49ef7e06SGarrett D'Amore static void
sfxge_rx_scale_kstat_fini(sfxge_t * sp)2179*49ef7e06SGarrett D'Amore sfxge_rx_scale_kstat_fini(sfxge_t *sp)
2180*49ef7e06SGarrett D'Amore {
2181*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2182*49ef7e06SGarrett D'Amore 
2183*49ef7e06SGarrett D'Amore 	/* Destroy the set */
2184*49ef7e06SGarrett D'Amore 	kstat_delete(srsp->srs_ksp);
2185*49ef7e06SGarrett D'Amore 	srsp->srs_ksp = NULL;
2186*49ef7e06SGarrett D'Amore }
2187*49ef7e06SGarrett D'Amore 
2188*49ef7e06SGarrett D'Amore 
2189*49ef7e06SGarrett D'Amore unsigned int
sfxge_rx_scale_prop_get(sfxge_t * sp)2190*49ef7e06SGarrett D'Amore sfxge_rx_scale_prop_get(sfxge_t *sp)
2191*49ef7e06SGarrett D'Amore {
2192*49ef7e06SGarrett D'Amore 	int rx_scale;
2193*49ef7e06SGarrett D'Amore 
2194*49ef7e06SGarrett D'Amore 	rx_scale = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
2195*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "rx_scale_count", SFXGE_RX_SCALE_MAX);
2196*49ef7e06SGarrett D'Amore 	/* 0 and all -ve numbers sets to number of logical CPUs */
2197*49ef7e06SGarrett D'Amore 	if (rx_scale <= 0)
2198*49ef7e06SGarrett D'Amore 		rx_scale = ncpus;
2199*49ef7e06SGarrett D'Amore 
2200*49ef7e06SGarrett D'Amore 	return (rx_scale);
2201*49ef7e06SGarrett D'Amore }
2202*49ef7e06SGarrett D'Amore 
2203*49ef7e06SGarrett D'Amore 
2204*49ef7e06SGarrett D'Amore static int
sfxge_rx_scale_init(sfxge_t * sp)2205*49ef7e06SGarrett D'Amore sfxge_rx_scale_init(sfxge_t *sp)
2206*49ef7e06SGarrett D'Amore {
2207*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2208*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2209*49ef7e06SGarrett D'Amore 	int rc;
2210*49ef7e06SGarrett D'Amore 
2211*49ef7e06SGarrett D'Amore 	ASSERT3U(srsp->srs_state, ==, SFXGE_RX_SCALE_UNINITIALIZED);
2212*49ef7e06SGarrett D'Amore 
2213*49ef7e06SGarrett D'Amore 	/* Create tables for CPU, core, cache and chip counts */
2214*49ef7e06SGarrett D'Amore 	srsp->srs_cpu = kmem_zalloc(sizeof (unsigned int) * NCPU, KM_SLEEP);
2215*49ef7e06SGarrett D'Amore 
2216*49ef7e06SGarrett D'Amore 	mutex_init(&(srsp->srs_lock), NULL, MUTEX_DRIVER, NULL);
2217*49ef7e06SGarrett D'Amore 
2218*49ef7e06SGarrett D'Amore 	/* We need at least one event queue */
2219*49ef7e06SGarrett D'Amore 	srsp->srs_count = sfxge_rx_scale_prop_get(sp);
2220*49ef7e06SGarrett D'Amore 	if (srsp->srs_count > sip->si_nalloc)
2221*49ef7e06SGarrett D'Amore 		srsp->srs_count = sip->si_nalloc;
2222*49ef7e06SGarrett D'Amore 	if (srsp->srs_count < 1)
2223*49ef7e06SGarrett D'Amore 		srsp->srs_count = 1;
2224*49ef7e06SGarrett D'Amore 
2225*49ef7e06SGarrett D'Amore 	/* Set up the kstats */
2226*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_rx_scale_kstat_init(sp)) != 0)
2227*49ef7e06SGarrett D'Amore 		goto fail1;
2228*49ef7e06SGarrett D'Amore 
2229*49ef7e06SGarrett D'Amore 	srsp->srs_state = SFXGE_RX_SCALE_INITIALIZED;
2230*49ef7e06SGarrett D'Amore 
2231*49ef7e06SGarrett D'Amore 	return (0);
2232*49ef7e06SGarrett D'Amore 
2233*49ef7e06SGarrett D'Amore fail1:
2234*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2235*49ef7e06SGarrett D'Amore 	mutex_destroy(&(srsp->srs_lock));
2236*49ef7e06SGarrett D'Amore 
2237*49ef7e06SGarrett D'Amore 	return (rc);
2238*49ef7e06SGarrett D'Amore }
2239*49ef7e06SGarrett D'Amore 
2240*49ef7e06SGarrett D'Amore void
sfxge_rx_scale_update(void * arg)2241*49ef7e06SGarrett D'Amore sfxge_rx_scale_update(void *arg)
2242*49ef7e06SGarrett D'Amore {
2243*49ef7e06SGarrett D'Amore 	sfxge_t *sp = arg;
2244*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2245*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip;
2246*49ef7e06SGarrett D'Amore 	processorid_t id;
2247*49ef7e06SGarrett D'Amore 	unsigned int count;
2248*49ef7e06SGarrett D'Amore 	unsigned int *tbl;
2249*49ef7e06SGarrett D'Amore 	unsigned int *rating;
2250*49ef7e06SGarrett D'Amore 	unsigned int entry;
2251*49ef7e06SGarrett D'Amore 	int rc;
2252*49ef7e06SGarrett D'Amore 
2253*49ef7e06SGarrett D'Amore 	mutex_enter(&(srsp->srs_lock));
2254*49ef7e06SGarrett D'Amore 
2255*49ef7e06SGarrett D'Amore 	if (srsp->srs_state != SFXGE_RX_SCALE_STARTED) {
2256*49ef7e06SGarrett D'Amore 		rc = EFAULT;
2257*49ef7e06SGarrett D'Amore 		goto fail1;
2258*49ef7e06SGarrett D'Amore 	}
2259*49ef7e06SGarrett D'Amore 
2260*49ef7e06SGarrett D'Amore 	if ((tbl =  kmem_zalloc(sizeof (unsigned int) * SFXGE_RX_SCALE_MAX,
2261*49ef7e06SGarrett D'Amore 	    KM_NOSLEEP)) == NULL) {
2262*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
2263*49ef7e06SGarrett D'Amore 		goto fail2;
2264*49ef7e06SGarrett D'Amore 	}
2265*49ef7e06SGarrett D'Amore 
2266*49ef7e06SGarrett D'Amore 	sip = &(sp->s_intr);
2267*49ef7e06SGarrett D'Amore 	if ((rating = kmem_zalloc(sizeof (unsigned int) * sip->si_nalloc,
2268*49ef7e06SGarrett D'Amore 	    KM_NOSLEEP)) == NULL) {
2269*49ef7e06SGarrett D'Amore 		rc = ENOMEM;
2270*49ef7e06SGarrett D'Amore 		goto fail3;
2271*49ef7e06SGarrett D'Amore 	}
2272*49ef7e06SGarrett D'Amore 
2273*49ef7e06SGarrett D'Amore 	mutex_enter(&cpu_lock);
2274*49ef7e06SGarrett D'Amore 
2275*49ef7e06SGarrett D'Amore 	/*
2276*49ef7e06SGarrett D'Amore 	 * Substract any current CPU, core, cache and chip usage from the
2277*49ef7e06SGarrett D'Amore 	 * global contention tables.
2278*49ef7e06SGarrett D'Amore 	 */
2279*49ef7e06SGarrett D'Amore 	for (id = 0; id < NCPU; id++) {
2280*49ef7e06SGarrett D'Amore 		ASSERT3U(sfxge_cpu[id], >=, srsp->srs_cpu[id]);
2281*49ef7e06SGarrett D'Amore 		sfxge_cpu[id] -= srsp->srs_cpu[id];
2282*49ef7e06SGarrett D'Amore 		srsp->srs_cpu[id] = 0;
2283*49ef7e06SGarrett D'Amore 	}
2284*49ef7e06SGarrett D'Amore 
2285*49ef7e06SGarrett D'Amore 	ASSERT(srsp->srs_count != 0);
2286*49ef7e06SGarrett D'Amore 
2287*49ef7e06SGarrett D'Amore 	/* Choose as many event queues as we need */
2288*49ef7e06SGarrett D'Amore 	for (count = 0; count < srsp->srs_count; count++) {
2289*49ef7e06SGarrett D'Amore 		unsigned int index;
2290*49ef7e06SGarrett D'Amore 		sfxge_evq_t *sep;
2291*49ef7e06SGarrett D'Amore 		unsigned int choice;
2292*49ef7e06SGarrett D'Amore 		unsigned int choice_rating;
2293*49ef7e06SGarrett D'Amore 
2294*49ef7e06SGarrett D'Amore 		bzero(rating, sizeof (unsigned int) * sip->si_nalloc);
2295*49ef7e06SGarrett D'Amore 
2296*49ef7e06SGarrett D'Amore 		/*
2297*49ef7e06SGarrett D'Amore 		 * Rate each event queue on its global level of CPU
2298*49ef7e06SGarrett D'Amore 		 * contention.
2299*49ef7e06SGarrett D'Amore 		 */
2300*49ef7e06SGarrett D'Amore 		for (index = 0; index < sip->si_nalloc; index++) {
2301*49ef7e06SGarrett D'Amore 			sep = sp->s_sep[index];
2302*49ef7e06SGarrett D'Amore 
2303*49ef7e06SGarrett D'Amore 			id = sep->se_cpu_id;
2304*49ef7e06SGarrett D'Amore 			rating[index] += sfxge_cpu[id];
2305*49ef7e06SGarrett D'Amore 		}
2306*49ef7e06SGarrett D'Amore 
2307*49ef7e06SGarrett D'Amore 		/* Choose the queue with the lowest CPU contention */
2308*49ef7e06SGarrett D'Amore 		choice = 0;
2309*49ef7e06SGarrett D'Amore 		choice_rating = rating[0];
2310*49ef7e06SGarrett D'Amore 
2311*49ef7e06SGarrett D'Amore 		for (index = 1; index < sip->si_nalloc; index++) {
2312*49ef7e06SGarrett D'Amore 			if (rating[index] < choice_rating) {
2313*49ef7e06SGarrett D'Amore 				choice = index;
2314*49ef7e06SGarrett D'Amore 				choice_rating = rating[index];
2315*49ef7e06SGarrett D'Amore 			}
2316*49ef7e06SGarrett D'Amore 		}
2317*49ef7e06SGarrett D'Amore 
2318*49ef7e06SGarrett D'Amore 		/* Add our choice to the condensed RSS table */
2319*49ef7e06SGarrett D'Amore 		tbl[count] = choice;
2320*49ef7e06SGarrett D'Amore 
2321*49ef7e06SGarrett D'Amore 		/* Add information to the global contention tables */
2322*49ef7e06SGarrett D'Amore 		sep = sp->s_sep[choice];
2323*49ef7e06SGarrett D'Amore 
2324*49ef7e06SGarrett D'Amore 		id = sep->se_cpu_id;
2325*49ef7e06SGarrett D'Amore 		srsp->srs_cpu[id]++;
2326*49ef7e06SGarrett D'Amore 		sfxge_cpu[id]++;
2327*49ef7e06SGarrett D'Amore 	}
2328*49ef7e06SGarrett D'Amore 
2329*49ef7e06SGarrett D'Amore 	mutex_exit(&cpu_lock);
2330*49ef7e06SGarrett D'Amore 
2331*49ef7e06SGarrett D'Amore 	/* Build the expanded RSS table */
2332*49ef7e06SGarrett D'Amore 	count = 0;
2333*49ef7e06SGarrett D'Amore 	for (entry = 0; entry < SFXGE_RX_SCALE_MAX; entry++) {
2334*49ef7e06SGarrett D'Amore 		unsigned int index;
2335*49ef7e06SGarrett D'Amore 
2336*49ef7e06SGarrett D'Amore 		index = tbl[count];
2337*49ef7e06SGarrett D'Amore 		count = (count + 1) % srsp->srs_count;
2338*49ef7e06SGarrett D'Amore 
2339*49ef7e06SGarrett D'Amore 		srsp->srs_tbl[entry] = index;
2340*49ef7e06SGarrett D'Amore 	}
2341*49ef7e06SGarrett D'Amore 
2342*49ef7e06SGarrett D'Amore 	/* Program the expanded RSS table into the hardware */
2343*49ef7e06SGarrett D'Amore 	(void) efx_rx_scale_tbl_set(sp->s_enp, srsp->srs_tbl,
2344*49ef7e06SGarrett D'Amore 	    SFXGE_RX_SCALE_MAX);
2345*49ef7e06SGarrett D'Amore 
2346*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2347*49ef7e06SGarrett D'Amore 	kmem_free(rating, sizeof (unsigned int) * sip->si_nalloc);
2348*49ef7e06SGarrett D'Amore 	kmem_free(tbl, sizeof (unsigned int) * SFXGE_RX_SCALE_MAX);
2349*49ef7e06SGarrett D'Amore 	return;
2350*49ef7e06SGarrett D'Amore 
2351*49ef7e06SGarrett D'Amore fail3:
2352*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
2353*49ef7e06SGarrett D'Amore 	kmem_free(tbl, sizeof (unsigned int) * SFXGE_RX_SCALE_MAX);
2354*49ef7e06SGarrett D'Amore fail2:
2355*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2356*49ef7e06SGarrett D'Amore fail1:
2357*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2358*49ef7e06SGarrett D'Amore 
2359*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2360*49ef7e06SGarrett D'Amore }
2361*49ef7e06SGarrett D'Amore 
2362*49ef7e06SGarrett D'Amore static int
sfxge_rx_scale_start(sfxge_t * sp)2363*49ef7e06SGarrett D'Amore sfxge_rx_scale_start(sfxge_t *sp)
2364*49ef7e06SGarrett D'Amore {
2365*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2366*49ef7e06SGarrett D'Amore 	int rc;
2367*49ef7e06SGarrett D'Amore 
2368*49ef7e06SGarrett D'Amore 	mutex_enter(&(srsp->srs_lock));
2369*49ef7e06SGarrett D'Amore 
2370*49ef7e06SGarrett D'Amore 	ASSERT3U(srsp->srs_state, ==, SFXGE_RX_SCALE_INITIALIZED);
2371*49ef7e06SGarrett D'Amore 
2372*49ef7e06SGarrett D'Amore 	/* Clear down the RSS table */
2373*49ef7e06SGarrett D'Amore 	bzero(srsp->srs_tbl, sizeof (unsigned int) * SFXGE_RX_SCALE_MAX);
2374*49ef7e06SGarrett D'Amore 
2375*49ef7e06SGarrett D'Amore 	(void) efx_rx_scale_tbl_set(sp->s_enp, srsp->srs_tbl,
2376*49ef7e06SGarrett D'Amore 	    SFXGE_RX_SCALE_MAX);
2377*49ef7e06SGarrett D'Amore 
2378*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_toeplitz_hash_init(sp)) != 0)
2379*49ef7e06SGarrett D'Amore 		goto fail1;
2380*49ef7e06SGarrett D'Amore 
2381*49ef7e06SGarrett D'Amore 	srsp->srs_state = SFXGE_RX_SCALE_STARTED;
2382*49ef7e06SGarrett D'Amore 
2383*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2384*49ef7e06SGarrett D'Amore 
2385*49ef7e06SGarrett D'Amore 	/* sfxge_t->s_state_lock held */
2386*49ef7e06SGarrett D'Amore 	(void) ddi_taskq_dispatch(sp->s_tqp, sfxge_rx_scale_update, sp,
2387*49ef7e06SGarrett D'Amore 	    DDI_SLEEP);
2388*49ef7e06SGarrett D'Amore 
2389*49ef7e06SGarrett D'Amore 	return (0);
2390*49ef7e06SGarrett D'Amore 
2391*49ef7e06SGarrett D'Amore fail1:
2392*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2393*49ef7e06SGarrett D'Amore 
2394*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2395*49ef7e06SGarrett D'Amore 
2396*49ef7e06SGarrett D'Amore 	return (rc);
2397*49ef7e06SGarrett D'Amore }
2398*49ef7e06SGarrett D'Amore 
2399*49ef7e06SGarrett D'Amore int
sfxge_rx_scale_count_get(sfxge_t * sp,unsigned int * countp)2400*49ef7e06SGarrett D'Amore sfxge_rx_scale_count_get(sfxge_t *sp, unsigned int *countp)
2401*49ef7e06SGarrett D'Amore {
2402*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2403*49ef7e06SGarrett D'Amore 	int rc;
2404*49ef7e06SGarrett D'Amore 
2405*49ef7e06SGarrett D'Amore 	mutex_enter(&(srsp->srs_lock));
2406*49ef7e06SGarrett D'Amore 
2407*49ef7e06SGarrett D'Amore 	if (srsp->srs_state != SFXGE_RX_SCALE_INITIALIZED &&
2408*49ef7e06SGarrett D'Amore 	    srsp->srs_state != SFXGE_RX_SCALE_STARTED) {
2409*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
2410*49ef7e06SGarrett D'Amore 		goto fail1;
2411*49ef7e06SGarrett D'Amore 	}
2412*49ef7e06SGarrett D'Amore 
2413*49ef7e06SGarrett D'Amore 	*countp = srsp->srs_count;
2414*49ef7e06SGarrett D'Amore 
2415*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2416*49ef7e06SGarrett D'Amore 
2417*49ef7e06SGarrett D'Amore 	return (0);
2418*49ef7e06SGarrett D'Amore 
2419*49ef7e06SGarrett D'Amore fail1:
2420*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2421*49ef7e06SGarrett D'Amore 
2422*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2423*49ef7e06SGarrett D'Amore 
2424*49ef7e06SGarrett D'Amore 	return (rc);
2425*49ef7e06SGarrett D'Amore }
2426*49ef7e06SGarrett D'Amore 
2427*49ef7e06SGarrett D'Amore int
sfxge_rx_scale_count_set(sfxge_t * sp,unsigned int count)2428*49ef7e06SGarrett D'Amore sfxge_rx_scale_count_set(sfxge_t *sp, unsigned int count)
2429*49ef7e06SGarrett D'Amore {
2430*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2431*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2432*49ef7e06SGarrett D'Amore 	int dispatch = 1;
2433*49ef7e06SGarrett D'Amore 	int rc;
2434*49ef7e06SGarrett D'Amore 
2435*49ef7e06SGarrett D'Amore 	if (count < 1 || count > sip->si_nalloc) {
2436*49ef7e06SGarrett D'Amore 		rc = EINVAL;
2437*49ef7e06SGarrett D'Amore 		goto fail1;
2438*49ef7e06SGarrett D'Amore 	}
2439*49ef7e06SGarrett D'Amore 
2440*49ef7e06SGarrett D'Amore 	mutex_enter(&(srsp->srs_lock));
2441*49ef7e06SGarrett D'Amore 
2442*49ef7e06SGarrett D'Amore 	if (srsp->srs_state != SFXGE_RX_SCALE_INITIALIZED &&
2443*49ef7e06SGarrett D'Amore 	    srsp->srs_state != SFXGE_RX_SCALE_STARTED) {
2444*49ef7e06SGarrett D'Amore 		rc = ENOTSUP;
2445*49ef7e06SGarrett D'Amore 		goto fail2;
2446*49ef7e06SGarrett D'Amore 	}
2447*49ef7e06SGarrett D'Amore 
2448*49ef7e06SGarrett D'Amore 	srsp->srs_count = count;
2449*49ef7e06SGarrett D'Amore 
2450*49ef7e06SGarrett D'Amore 	if (srsp->srs_state != SFXGE_RX_SCALE_STARTED)
2451*49ef7e06SGarrett D'Amore 		dispatch = 0;
2452*49ef7e06SGarrett D'Amore 
2453*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2454*49ef7e06SGarrett D'Amore 
2455*49ef7e06SGarrett D'Amore 	if (dispatch)
2456*49ef7e06SGarrett D'Amore 		/* no locks held */
2457*49ef7e06SGarrett D'Amore 		(void) ddi_taskq_dispatch(sp->s_tqp, sfxge_rx_scale_update, sp,
2458*49ef7e06SGarrett D'Amore 		    DDI_SLEEP);
2459*49ef7e06SGarrett D'Amore 
2460*49ef7e06SGarrett D'Amore 	return (0);
2461*49ef7e06SGarrett D'Amore 
2462*49ef7e06SGarrett D'Amore fail2:
2463*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2464*49ef7e06SGarrett D'Amore 
2465*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2466*49ef7e06SGarrett D'Amore 
2467*49ef7e06SGarrett D'Amore fail1:
2468*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2469*49ef7e06SGarrett D'Amore 
2470*49ef7e06SGarrett D'Amore 	return (rc);
2471*49ef7e06SGarrett D'Amore }
2472*49ef7e06SGarrett D'Amore 
2473*49ef7e06SGarrett D'Amore static void
sfxge_rx_scale_stop(sfxge_t * sp)2474*49ef7e06SGarrett D'Amore sfxge_rx_scale_stop(sfxge_t *sp)
2475*49ef7e06SGarrett D'Amore {
2476*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2477*49ef7e06SGarrett D'Amore 	processorid_t id;
2478*49ef7e06SGarrett D'Amore 
2479*49ef7e06SGarrett D'Amore 	mutex_enter(&(srsp->srs_lock));
2480*49ef7e06SGarrett D'Amore 
2481*49ef7e06SGarrett D'Amore 	ASSERT3U(srsp->srs_state, ==, SFXGE_RX_SCALE_STARTED);
2482*49ef7e06SGarrett D'Amore 
2483*49ef7e06SGarrett D'Amore 	srsp->srs_state = SFXGE_RX_SCALE_INITIALIZED;
2484*49ef7e06SGarrett D'Amore 
2485*49ef7e06SGarrett D'Amore 	mutex_enter(&cpu_lock);
2486*49ef7e06SGarrett D'Amore 
2487*49ef7e06SGarrett D'Amore 	/*
2488*49ef7e06SGarrett D'Amore 	 * Substract any current CPU, core, cache and chip usage from the
2489*49ef7e06SGarrett D'Amore 	 * global contention tables.
2490*49ef7e06SGarrett D'Amore 	 */
2491*49ef7e06SGarrett D'Amore 	for (id = 0; id < NCPU; id++) {
2492*49ef7e06SGarrett D'Amore 		ASSERT3U(sfxge_cpu[id], >=, srsp->srs_cpu[id]);
2493*49ef7e06SGarrett D'Amore 		sfxge_cpu[id] -= srsp->srs_cpu[id];
2494*49ef7e06SGarrett D'Amore 		srsp->srs_cpu[id] = 0;
2495*49ef7e06SGarrett D'Amore 	}
2496*49ef7e06SGarrett D'Amore 
2497*49ef7e06SGarrett D'Amore 	mutex_exit(&cpu_lock);
2498*49ef7e06SGarrett D'Amore 
2499*49ef7e06SGarrett D'Amore 	/* Clear down the RSS table */
2500*49ef7e06SGarrett D'Amore 	bzero(srsp->srs_tbl, sizeof (unsigned int) * SFXGE_RX_SCALE_MAX);
2501*49ef7e06SGarrett D'Amore 
2502*49ef7e06SGarrett D'Amore 	(void) efx_rx_scale_tbl_set(sp->s_enp, srsp->srs_tbl,
2503*49ef7e06SGarrett D'Amore 	    SFXGE_RX_SCALE_MAX);
2504*49ef7e06SGarrett D'Amore 
2505*49ef7e06SGarrett D'Amore 	mutex_exit(&(srsp->srs_lock));
2506*49ef7e06SGarrett D'Amore }
2507*49ef7e06SGarrett D'Amore 
2508*49ef7e06SGarrett D'Amore static void
sfxge_rx_scale_fini(sfxge_t * sp)2509*49ef7e06SGarrett D'Amore sfxge_rx_scale_fini(sfxge_t *sp)
2510*49ef7e06SGarrett D'Amore {
2511*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_t *srsp = &(sp->s_rx_scale);
2512*49ef7e06SGarrett D'Amore 
2513*49ef7e06SGarrett D'Amore 	ASSERT3U(srsp->srs_state, ==, SFXGE_RX_SCALE_INITIALIZED);
2514*49ef7e06SGarrett D'Amore 
2515*49ef7e06SGarrett D'Amore 	srsp->srs_state = SFXGE_RX_SCALE_UNINITIALIZED;
2516*49ef7e06SGarrett D'Amore 
2517*49ef7e06SGarrett D'Amore 	/* Tear down the kstats */
2518*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_kstat_fini(sp);
2519*49ef7e06SGarrett D'Amore 
2520*49ef7e06SGarrett D'Amore 	srsp->srs_count = 0;
2521*49ef7e06SGarrett D'Amore 
2522*49ef7e06SGarrett D'Amore 	mutex_destroy(&(srsp->srs_lock));
2523*49ef7e06SGarrett D'Amore 
2524*49ef7e06SGarrett D'Amore 	/* Destroy tables */
2525*49ef7e06SGarrett D'Amore 	kmem_free(srsp->srs_cpu, sizeof (unsigned int) * NCPU);
2526*49ef7e06SGarrett D'Amore 	srsp->srs_cpu = NULL;
2527*49ef7e06SGarrett D'Amore 
2528*49ef7e06SGarrett D'Amore 	sfxge_toeplitz_hash_fini(sp);
2529*49ef7e06SGarrett D'Amore }
2530*49ef7e06SGarrett D'Amore 
2531*49ef7e06SGarrett D'Amore int
sfxge_rx_init(sfxge_t * sp)2532*49ef7e06SGarrett D'Amore sfxge_rx_init(sfxge_t *sp)
2533*49ef7e06SGarrett D'Amore {
2534*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2535*49ef7e06SGarrett D'Amore 	char name[MAXNAMELEN];
2536*49ef7e06SGarrett D'Amore 	int index;
2537*49ef7e06SGarrett D'Amore 	int rc;
2538*49ef7e06SGarrett D'Amore 
2539*49ef7e06SGarrett D'Amore 	if (sip->si_state == SFXGE_INTR_UNINITIALIZED) {
2540*49ef7e06SGarrett D'Amore 		rc = EINVAL;
2541*49ef7e06SGarrett D'Amore 		goto fail1;
2542*49ef7e06SGarrett D'Amore 	}
2543*49ef7e06SGarrett D'Amore 
2544*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_rx_scale_init(sp)) != 0)
2545*49ef7e06SGarrett D'Amore 		goto fail2;
2546*49ef7e06SGarrett D'Amore 
2547*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_rx_packet_cache",
2548*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
2549*49ef7e06SGarrett D'Amore 
2550*49ef7e06SGarrett D'Amore 	sp->s_rpc = kmem_cache_create(name, sizeof (sfxge_rx_packet_t),
2551*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, sfxge_rx_packet_ctor, sfxge_rx_packet_dtor,
2552*49ef7e06SGarrett D'Amore 	    NULL, sp, NULL, 0);
2553*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_rpc != NULL);
2554*49ef7e06SGarrett D'Amore 
2555*49ef7e06SGarrett D'Amore 	(void) snprintf(name, MAXNAMELEN - 1, "%s%d_rxq_cache",
2556*49ef7e06SGarrett D'Amore 	    ddi_driver_name(sp->s_dip), ddi_get_instance(sp->s_dip));
2557*49ef7e06SGarrett D'Amore 
2558*49ef7e06SGarrett D'Amore 	sp->s_rqc = kmem_cache_create(name, sizeof (sfxge_rxq_t),
2559*49ef7e06SGarrett D'Amore 	    SFXGE_CPU_CACHE_SIZE, sfxge_rx_qctor, sfxge_rx_qdtor, NULL, sp,
2560*49ef7e06SGarrett D'Amore 	    NULL, 0);
2561*49ef7e06SGarrett D'Amore 	ASSERT(sp->s_rqc != NULL);
2562*49ef7e06SGarrett D'Amore 
2563*49ef7e06SGarrett D'Amore 	sp->s_rx_pkt_mem_max = ddi_prop_get_int64(DDI_DEV_T_ANY, sp->s_dip,
2564*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "rx_pkt_mem_max", 0); /* disabled */
2565*49ef7e06SGarrett D'Amore 
2566*49ef7e06SGarrett D'Amore 	/* Initialize the receive queue(s) */
2567*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
2568*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_rx_qinit(sp, index)) != 0)
2569*49ef7e06SGarrett D'Amore 			goto fail3;
2570*49ef7e06SGarrett D'Amore 	}
2571*49ef7e06SGarrett D'Amore 
2572*49ef7e06SGarrett D'Amore 	sp->s_rx_coalesce_mode = ddi_prop_get_int(DDI_DEV_T_ANY, sp->s_dip,
2573*49ef7e06SGarrett D'Amore 	    DDI_PROP_DONTPASS, "rx_coalesce_mode", SFXGE_RX_COALESCE_OFF);
2574*49ef7e06SGarrett D'Amore 
2575*49ef7e06SGarrett D'Amore 	return (0);
2576*49ef7e06SGarrett D'Amore 
2577*49ef7e06SGarrett D'Amore fail3:
2578*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
2579*49ef7e06SGarrett D'Amore 
2580*49ef7e06SGarrett D'Amore 	/* Tear down the receive queue(s) */
2581*49ef7e06SGarrett D'Amore 	while (--index >= 0)
2582*49ef7e06SGarrett D'Amore 		sfxge_rx_qfini(sp, index);
2583*49ef7e06SGarrett D'Amore 
2584*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_rqc);
2585*49ef7e06SGarrett D'Amore 	sp->s_rqc = NULL;
2586*49ef7e06SGarrett D'Amore 
2587*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_rpc);
2588*49ef7e06SGarrett D'Amore 	sp->s_rpc = NULL;
2589*49ef7e06SGarrett D'Amore 
2590*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_fini(sp);
2591*49ef7e06SGarrett D'Amore 
2592*49ef7e06SGarrett D'Amore fail2:
2593*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2594*49ef7e06SGarrett D'Amore fail1:
2595*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2596*49ef7e06SGarrett D'Amore 
2597*49ef7e06SGarrett D'Amore 	return (rc);
2598*49ef7e06SGarrett D'Amore }
2599*49ef7e06SGarrett D'Amore 
2600*49ef7e06SGarrett D'Amore int
sfxge_rx_start(sfxge_t * sp)2601*49ef7e06SGarrett D'Amore sfxge_rx_start(sfxge_t *sp)
2602*49ef7e06SGarrett D'Amore {
2603*49ef7e06SGarrett D'Amore 	sfxge_mac_t *smp = &(sp->s_mac);
2604*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip;
2605*49ef7e06SGarrett D'Amore 	const efx_nic_cfg_t *encp;
2606*49ef7e06SGarrett D'Amore 	size_t hdrlen, align;
2607*49ef7e06SGarrett D'Amore 	int index;
2608*49ef7e06SGarrett D'Amore 	int rc;
2609*49ef7e06SGarrett D'Amore 
2610*49ef7e06SGarrett D'Amore 	mutex_enter(&(smp->sm_lock));
2611*49ef7e06SGarrett D'Amore 
2612*49ef7e06SGarrett D'Amore 	/* Calculate the receive packet buffer size and alignment */
2613*49ef7e06SGarrett D'Amore 	sp->s_rx_buffer_size = EFX_MAC_PDU(sp->s_mtu);
2614*49ef7e06SGarrett D'Amore 
2615*49ef7e06SGarrett D'Amore 	encp = efx_nic_cfg_get(sp->s_enp);
2616*49ef7e06SGarrett D'Amore 
2617*49ef7e06SGarrett D'Amore 	/* Packet buffer allocations are cache line aligned */
2618*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT3U(encp->enc_rx_buf_align_start, <=, SFXGE_CPU_CACHE_SIZE);
2619*49ef7e06SGarrett D'Amore 
2620*49ef7e06SGarrett D'Amore 	if (sp->s_family == EFX_FAMILY_HUNTINGTON) {
2621*49ef7e06SGarrett D'Amore 		sp->s_rx_prefix_size = encp->enc_rx_prefix_size;
2622*49ef7e06SGarrett D'Amore 
2623*49ef7e06SGarrett D'Amore 		hdrlen = sp->s_rx_prefix_size + sizeof (struct ether_header);
2624*49ef7e06SGarrett D'Amore 
2625*49ef7e06SGarrett D'Amore 		/* Ensure IP headers are 32bit aligned */
2626*49ef7e06SGarrett D'Amore 		sp->s_rx_buffer_align = P2ROUNDUP(hdrlen, 4) - hdrlen;
2627*49ef7e06SGarrett D'Amore 		sp->s_rx_buffer_size += sp->s_rx_buffer_align;
2628*49ef7e06SGarrett D'Amore 
2629*49ef7e06SGarrett D'Amore 	} else if (encp->enc_features & EFX_FEATURE_LFSR_HASH_INSERT) {
2630*49ef7e06SGarrett D'Amore 		sp->s_rx_prefix_size = encp->enc_rx_prefix_size;
2631*49ef7e06SGarrett D'Amore 
2632*49ef7e06SGarrett D'Amore 		/*
2633*49ef7e06SGarrett D'Amore 		 * Place the start of the buffer a prefix length minus 2
2634*49ef7e06SGarrett D'Amore 		 * before the start of a cache line. This ensures that the
2635*49ef7e06SGarrett D'Amore 		 * last two bytes of the prefix (which is where the LFSR hash
2636*49ef7e06SGarrett D'Amore 		 * is located) are in the same cache line as the headers, and
2637*49ef7e06SGarrett D'Amore 		 * the IP header is 32-bit aligned.
2638*49ef7e06SGarrett D'Amore 		 */
2639*49ef7e06SGarrett D'Amore 		sp->s_rx_buffer_align =
2640*49ef7e06SGarrett D'Amore 		    SFXGE_CPU_CACHE_SIZE - (encp->enc_rx_prefix_size - 2);
2641*49ef7e06SGarrett D'Amore 		sp->s_rx_buffer_size += sp->s_rx_buffer_align;
2642*49ef7e06SGarrett D'Amore 	} else {
2643*49ef7e06SGarrett D'Amore 		sp->s_rx_prefix_size = 0;
2644*49ef7e06SGarrett D'Amore 
2645*49ef7e06SGarrett D'Amore 		/*
2646*49ef7e06SGarrett D'Amore 		 * Place the start of the buffer 2 bytes after a cache line
2647*49ef7e06SGarrett D'Amore 		 * boundary so that the headers fit into the cache line and
2648*49ef7e06SGarrett D'Amore 		 * the IP header is 32-bit aligned.
2649*49ef7e06SGarrett D'Amore 		 */
2650*49ef7e06SGarrett D'Amore 		hdrlen = sp->s_rx_prefix_size + sizeof (struct ether_header);
2651*49ef7e06SGarrett D'Amore 
2652*49ef7e06SGarrett D'Amore 		sp->s_rx_buffer_align = P2ROUNDUP(hdrlen, 4) - hdrlen;
2653*49ef7e06SGarrett D'Amore 		sp->s_rx_buffer_size += sp->s_rx_buffer_align;
2654*49ef7e06SGarrett D'Amore 	}
2655*49ef7e06SGarrett D'Amore 
2656*49ef7e06SGarrett D'Amore 	/* Align end of packet buffer for RX DMA end padding */
2657*49ef7e06SGarrett D'Amore 	align = MAX(1, encp->enc_rx_buf_align_end);
2658*49ef7e06SGarrett D'Amore 	EFSYS_ASSERT(ISP2(align));
2659*49ef7e06SGarrett D'Amore 	sp->s_rx_buffer_size = P2ROUNDUP(sp->s_rx_buffer_size, align);
2660*49ef7e06SGarrett D'Amore 
2661*49ef7e06SGarrett D'Amore 	/* Initialize the receive module */
2662*49ef7e06SGarrett D'Amore 	if ((rc = efx_rx_init(sp->s_enp)) != 0)
2663*49ef7e06SGarrett D'Amore 		goto fail1;
2664*49ef7e06SGarrett D'Amore 
2665*49ef7e06SGarrett D'Amore 	mutex_exit(&(smp->sm_lock));
2666*49ef7e06SGarrett D'Amore 
2667*49ef7e06SGarrett D'Amore 	if ((rc = sfxge_rx_scale_start(sp)) != 0)
2668*49ef7e06SGarrett D'Amore 		goto fail2;
2669*49ef7e06SGarrett D'Amore 
2670*49ef7e06SGarrett D'Amore 	/* Start the receive queue(s) */
2671*49ef7e06SGarrett D'Amore 	sip = &(sp->s_intr);
2672*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
2673*49ef7e06SGarrett D'Amore 		if ((rc = sfxge_rx_qstart(sp, index)) != 0)
2674*49ef7e06SGarrett D'Amore 			goto fail3;
2675*49ef7e06SGarrett D'Amore 	}
2676*49ef7e06SGarrett D'Amore 
2677*49ef7e06SGarrett D'Amore 	ASSERT3U(sp->s_srp[0]->sr_state, ==, SFXGE_RXQ_STARTED);
2678*49ef7e06SGarrett D'Amore 	/* It is sufficient to have Rx scale initialized */
2679*49ef7e06SGarrett D'Amore 	ASSERT3U(sp->s_rx_scale.srs_state, ==, SFXGE_RX_SCALE_STARTED);
2680*49ef7e06SGarrett D'Amore 	rc = efx_mac_filter_default_rxq_set(sp->s_enp, sp->s_srp[0]->sr_erp,
2681*49ef7e06SGarrett D'Amore 	    sp->s_rx_scale.srs_count > 1);
2682*49ef7e06SGarrett D'Amore 	if (rc != 0)
2683*49ef7e06SGarrett D'Amore 		goto fail4;
2684*49ef7e06SGarrett D'Amore 
2685*49ef7e06SGarrett D'Amore 	return (0);
2686*49ef7e06SGarrett D'Amore 
2687*49ef7e06SGarrett D'Amore fail4:
2688*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail4);
2689*49ef7e06SGarrett D'Amore 
2690*49ef7e06SGarrett D'Amore fail3:
2691*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail3);
2692*49ef7e06SGarrett D'Amore 
2693*49ef7e06SGarrett D'Amore 	/* Stop the receive queue(s) */
2694*49ef7e06SGarrett D'Amore 	while (--index >= 0)
2695*49ef7e06SGarrett D'Amore 		sfxge_rx_qstop(sp, index);
2696*49ef7e06SGarrett D'Amore 
2697*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_stop(sp);
2698*49ef7e06SGarrett D'Amore 
2699*49ef7e06SGarrett D'Amore fail2:
2700*49ef7e06SGarrett D'Amore 	DTRACE_PROBE(fail2);
2701*49ef7e06SGarrett D'Amore 
2702*49ef7e06SGarrett D'Amore 	mutex_enter(&(smp->sm_lock));
2703*49ef7e06SGarrett D'Amore 
2704*49ef7e06SGarrett D'Amore 	/* Tear down the receive module */
2705*49ef7e06SGarrett D'Amore 	efx_rx_fini(sp->s_enp);
2706*49ef7e06SGarrett D'Amore 
2707*49ef7e06SGarrett D'Amore fail1:
2708*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2709*49ef7e06SGarrett D'Amore 
2710*49ef7e06SGarrett D'Amore 	mutex_exit(&(smp->sm_lock));
2711*49ef7e06SGarrett D'Amore 
2712*49ef7e06SGarrett D'Amore 	return (rc);
2713*49ef7e06SGarrett D'Amore }
2714*49ef7e06SGarrett D'Amore 
2715*49ef7e06SGarrett D'Amore void
sfxge_rx_coalesce_mode_get(sfxge_t * sp,sfxge_rx_coalesce_mode_t * modep)2716*49ef7e06SGarrett D'Amore sfxge_rx_coalesce_mode_get(sfxge_t *sp, sfxge_rx_coalesce_mode_t *modep)
2717*49ef7e06SGarrett D'Amore {
2718*49ef7e06SGarrett D'Amore 	*modep = sp->s_rx_coalesce_mode;
2719*49ef7e06SGarrett D'Amore }
2720*49ef7e06SGarrett D'Amore 
2721*49ef7e06SGarrett D'Amore int
sfxge_rx_coalesce_mode_set(sfxge_t * sp,sfxge_rx_coalesce_mode_t mode)2722*49ef7e06SGarrett D'Amore sfxge_rx_coalesce_mode_set(sfxge_t *sp, sfxge_rx_coalesce_mode_t mode)
2723*49ef7e06SGarrett D'Amore {
2724*49ef7e06SGarrett D'Amore 	int rc;
2725*49ef7e06SGarrett D'Amore 
2726*49ef7e06SGarrett D'Amore 	switch (mode) {
2727*49ef7e06SGarrett D'Amore 	case SFXGE_RX_COALESCE_OFF:
2728*49ef7e06SGarrett D'Amore 	case SFXGE_RX_COALESCE_DISALLOW_PUSH:
2729*49ef7e06SGarrett D'Amore 	case SFXGE_RX_COALESCE_ALLOW_PUSH:
2730*49ef7e06SGarrett D'Amore 		break;
2731*49ef7e06SGarrett D'Amore 
2732*49ef7e06SGarrett D'Amore 	default:
2733*49ef7e06SGarrett D'Amore 		rc = EINVAL;
2734*49ef7e06SGarrett D'Amore 		goto fail1;
2735*49ef7e06SGarrett D'Amore 	}
2736*49ef7e06SGarrett D'Amore 
2737*49ef7e06SGarrett D'Amore 	sp->s_rx_coalesce_mode = mode;
2738*49ef7e06SGarrett D'Amore 
2739*49ef7e06SGarrett D'Amore 	return (0);
2740*49ef7e06SGarrett D'Amore 
2741*49ef7e06SGarrett D'Amore fail1:
2742*49ef7e06SGarrett D'Amore 	DTRACE_PROBE1(fail1, int, rc);
2743*49ef7e06SGarrett D'Amore 
2744*49ef7e06SGarrett D'Amore 	return (rc);
2745*49ef7e06SGarrett D'Amore }
2746*49ef7e06SGarrett D'Amore 
2747*49ef7e06SGarrett D'Amore void
sfxge_rx_stop(sfxge_t * sp)2748*49ef7e06SGarrett D'Amore sfxge_rx_stop(sfxge_t *sp)
2749*49ef7e06SGarrett D'Amore {
2750*49ef7e06SGarrett D'Amore 	sfxge_mac_t *smp = &(sp->s_mac);
2751*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2752*49ef7e06SGarrett D'Amore 	efx_nic_t *enp = sp->s_enp;
2753*49ef7e06SGarrett D'Amore 	int index;
2754*49ef7e06SGarrett D'Amore 
2755*49ef7e06SGarrett D'Amore 	ASSERT(mutex_owned(&(sp->s_state_lock)));
2756*49ef7e06SGarrett D'Amore 
2757*49ef7e06SGarrett D'Amore 	efx_mac_filter_default_rxq_clear(enp);
2758*49ef7e06SGarrett D'Amore 
2759*49ef7e06SGarrett D'Amore 	/* Stop the receive queue(s) */
2760*49ef7e06SGarrett D'Amore 	index = sip->si_nalloc;
2761*49ef7e06SGarrett D'Amore 	while (--index >= 0) {
2762*49ef7e06SGarrett D'Amore 		/* TBD: Flush RXQs in parallel; HW has limit + may need retry */
2763*49ef7e06SGarrett D'Amore 		sfxge_rx_qstop(sp, index);
2764*49ef7e06SGarrett D'Amore 	}
2765*49ef7e06SGarrett D'Amore 
2766*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_stop(sp);
2767*49ef7e06SGarrett D'Amore 
2768*49ef7e06SGarrett D'Amore 	mutex_enter(&(smp->sm_lock));
2769*49ef7e06SGarrett D'Amore 
2770*49ef7e06SGarrett D'Amore 	/* Tear down the receive module */
2771*49ef7e06SGarrett D'Amore 	efx_rx_fini(enp);
2772*49ef7e06SGarrett D'Amore 
2773*49ef7e06SGarrett D'Amore 	sp->s_rx_buffer_align = 0;
2774*49ef7e06SGarrett D'Amore 	sp->s_rx_prefix_size = 0;
2775*49ef7e06SGarrett D'Amore 	sp->s_rx_buffer_size = 0;
2776*49ef7e06SGarrett D'Amore 
2777*49ef7e06SGarrett D'Amore 	mutex_exit(&(smp->sm_lock));
2778*49ef7e06SGarrett D'Amore }
2779*49ef7e06SGarrett D'Amore 
2780*49ef7e06SGarrett D'Amore unsigned int
sfxge_rx_loaned(sfxge_t * sp)2781*49ef7e06SGarrett D'Amore sfxge_rx_loaned(sfxge_t *sp)
2782*49ef7e06SGarrett D'Amore {
2783*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2784*49ef7e06SGarrett D'Amore 	int index;
2785*49ef7e06SGarrett D'Amore 	unsigned int loaned;
2786*49ef7e06SGarrett D'Amore 
2787*49ef7e06SGarrett D'Amore 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
2788*49ef7e06SGarrett D'Amore 
2789*49ef7e06SGarrett D'Amore 	loaned = 0;
2790*49ef7e06SGarrett D'Amore 	for (index = 0; index < sip->si_nalloc; index++) {
2791*49ef7e06SGarrett D'Amore 		sfxge_rxq_t *srp = sp->s_srp[index];
2792*49ef7e06SGarrett D'Amore 		sfxge_evq_t *sep = sp->s_sep[srp->sr_index];
2793*49ef7e06SGarrett D'Amore 
2794*49ef7e06SGarrett D'Amore 		mutex_enter(&(sep->se_lock));
2795*49ef7e06SGarrett D'Amore 
2796*49ef7e06SGarrett D'Amore 		loaned += sfxge_rx_qfpp_swizzle(srp);
2797*49ef7e06SGarrett D'Amore 
2798*49ef7e06SGarrett D'Amore 		mutex_exit(&(sep->se_lock));
2799*49ef7e06SGarrett D'Amore 	}
2800*49ef7e06SGarrett D'Amore 
2801*49ef7e06SGarrett D'Amore 	return (loaned);
2802*49ef7e06SGarrett D'Amore }
2803*49ef7e06SGarrett D'Amore 
2804*49ef7e06SGarrett D'Amore void
sfxge_rx_fini(sfxge_t * sp)2805*49ef7e06SGarrett D'Amore sfxge_rx_fini(sfxge_t *sp)
2806*49ef7e06SGarrett D'Amore {
2807*49ef7e06SGarrett D'Amore 	sfxge_intr_t *sip = &(sp->s_intr);
2808*49ef7e06SGarrett D'Amore 	int index;
2809*49ef7e06SGarrett D'Amore 
2810*49ef7e06SGarrett D'Amore 	ASSERT3U(sip->si_state, ==, SFXGE_INTR_INITIALIZED);
2811*49ef7e06SGarrett D'Amore 
2812*49ef7e06SGarrett D'Amore 	sp->s_rx_coalesce_mode = SFXGE_RX_COALESCE_OFF;
2813*49ef7e06SGarrett D'Amore 
2814*49ef7e06SGarrett D'Amore 	/* Tear down the receive queue(s) */
2815*49ef7e06SGarrett D'Amore 	index = sip->si_nalloc;
2816*49ef7e06SGarrett D'Amore 	while (--index >= 0)
2817*49ef7e06SGarrett D'Amore 		sfxge_rx_qfini(sp, index);
2818*49ef7e06SGarrett D'Amore 
2819*49ef7e06SGarrett D'Amore 	ASSERT3U(sp->s_rx_pkt_mem_alloc, ==, 0);
2820*49ef7e06SGarrett D'Amore 
2821*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_rqc);
2822*49ef7e06SGarrett D'Amore 	sp->s_rqc = NULL;
2823*49ef7e06SGarrett D'Amore 
2824*49ef7e06SGarrett D'Amore 	kmem_cache_destroy(sp->s_rpc);
2825*49ef7e06SGarrett D'Amore 	sp->s_rpc = NULL;
2826*49ef7e06SGarrett D'Amore 
2827*49ef7e06SGarrett D'Amore 	sfxge_rx_scale_fini(sp);
2828*49ef7e06SGarrett D'Amore }
2829